bluez-4.101/0000755000000000000000000000000011771120003007577 500000000000000bluez-4.101/cups/0000755000000000000000000000000011771120004010552 500000000000000bluez-4.101/cups/cups.h0000644000000000000000000000331111376221745011632 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ enum { /**** Backend exit codes ****/ CUPS_BACKEND_OK = 0, /* Job completed successfully */ CUPS_BACKEND_FAILED = 1, /* Job failed, use error-policy */ CUPS_BACKEND_AUTH_REQUIRED = 2, /* Job failed, authentication required */ CUPS_BACKEND_HOLD = 3, /* Job failed, hold job */ CUPS_BACKEND_STOP = 4, /* Job failed, stop queue */ CUPS_BACKEND_CANCEL = 5, /* Job failed, cancel job */ CUPS_BACKEND_RETRY = 6, /* Failure requires us to retry (BlueZ specific) */ }; int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class); int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class); bluez-4.101/cups/spp.c0000644000000000000000000000551011376221745011460 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "cups.h" int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies, const char *cups_class) { struct sockaddr_rc addr; unsigned char buf[2048]; int i, sk, err, len; if ((sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { perror("ERROR: Can't create socket"); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, src); addr.rc_channel = 0; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("ERROR: Can't bind socket"); close(sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, dst); addr.rc_channel = channel; if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("ERROR: Can't connect to device"); close(sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } fputs("STATE: -connecting-to-device\n", stderr); /* Ignore SIGTERM signals if printing from stdin */ if (fd == 0) { #ifdef HAVE_SIGSET sigset(SIGTERM, SIG_IGN); #elif defined(HAVE_SIGACTION) memset(&action, 0, sizeof(action)); sigemptyset(&action.sa_mask); action.sa_handler = SIG_IGN; sigaction(SIGTERM, &action, NULL); #else signal(SIGTERM, SIG_IGN); #endif /* HAVE_SIGSET */ } for (i = 0; i < copies; i++) { if (fd != 0) { fprintf(stderr, "PAGE: 1 1\n"); lseek(fd, 0, SEEK_SET); } while ((len = read(fd, buf, sizeof(buf))) > 0) { err = write(sk, buf, len); if (err < 0) { perror("ERROR: Error writing to device"); close(sk); return CUPS_BACKEND_FAILED; } } } close(sk); return CUPS_BACKEND_OK; } bluez-4.101/cups/hcrp.c0000644000000000000000000002045211571052274011610 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "cups.h" #define HCRP_PDU_CREDIT_GRANT 0x0001 #define HCRP_PDU_CREDIT_REQUEST 0x0002 #define HCRP_PDU_GET_LPT_STATUS 0x0005 #define HCRP_STATUS_FEATURE_UNSUPPORTED 0x0000 #define HCRP_STATUS_SUCCESS 0x0001 #define HCRP_STATUS_CREDIT_SYNC_ERROR 0x0002 #define HCRP_STATUS_GENERIC_FAILURE 0xffff struct hcrp_pdu_hdr { uint16_t pid; uint16_t tid; uint16_t plen; } __attribute__ ((packed)); #define HCRP_PDU_HDR_SIZE 6 struct hcrp_credit_grant_cp { uint32_t credit; } __attribute__ ((packed)); #define HCRP_CREDIT_GRANT_CP_SIZE 4 struct hcrp_credit_grant_rp { uint16_t status; } __attribute__ ((packed)); #define HCRP_CREDIT_GRANT_RP_SIZE 2 struct hcrp_credit_request_rp { uint16_t status; uint32_t credit; } __attribute__ ((packed)); #define HCRP_CREDIT_REQUEST_RP_SIZE 6 struct hcrp_get_lpt_status_rp { uint16_t status; uint8_t lpt_status; } __attribute__ ((packed)); #define HCRP_GET_LPT_STATUS_RP_SIZE 3 static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit) { struct hcrp_pdu_hdr hdr; struct hcrp_credit_grant_cp cp; struct hcrp_credit_grant_rp rp; unsigned char buf[128]; int len; hdr.pid = htons(HCRP_PDU_CREDIT_GRANT); hdr.tid = htons(tid); hdr.plen = htons(HCRP_CREDIT_GRANT_CP_SIZE); cp.credit = credit; memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE); memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE); len = write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE); if (len < 0) return len; len = read(sk, buf, sizeof(buf)); if (len < 0) return len; memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE); memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE); if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) { errno = EIO; return -1; } return 0; } static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit) { struct hcrp_pdu_hdr hdr; struct hcrp_credit_request_rp rp; unsigned char buf[128]; int len; hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST); hdr.tid = htons(tid); hdr.plen = htons(0); memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE); len = write(sk, buf, HCRP_PDU_HDR_SIZE); if (len < 0) return len; len = read(sk, buf, sizeof(buf)); if (len < 0) return len; memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE); memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE); if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) { errno = EIO; return -1; } if (credit) *credit = ntohl(rp.credit); return 0; } static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status) { struct hcrp_pdu_hdr hdr; struct hcrp_get_lpt_status_rp rp; unsigned char buf[128]; int len; hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS); hdr.tid = htons(tid); hdr.plen = htons(0); memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE); len = write(sk, buf, HCRP_PDU_HDR_SIZE); if (len < 0) return len; len = read(sk, buf, sizeof(buf)); if (len < 0) return len; memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE); memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE); if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) { errno = EIO; return -1; } if (lpt_status) *lpt_status = rp.lpt_status; return 0; } static inline int hcrp_get_next_tid(int tid) { if (tid > 0xf000) return 0; else return tid + 1; } int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies, const char *cups_class) { struct sockaddr_l2 addr; struct l2cap_options opts; socklen_t size; unsigned char buf[2048]; int i, ctrl_sk, data_sk, count, len, timeout = 0; unsigned int mtu; uint8_t status; uint16_t tid = 0; uint32_t tmp, credit = 0; if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) { perror("ERROR: Can't create socket"); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; bacpy(&addr.l2_bdaddr, src); if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("ERROR: Can't bind socket"); close(ctrl_sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; bacpy(&addr.l2_bdaddr, dst); addr.l2_psm = htobs(ctrl_psm); if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("ERROR: Can't connect to device"); close(ctrl_sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) { perror("ERROR: Can't create socket"); close(ctrl_sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; bacpy(&addr.l2_bdaddr, src); if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("ERROR: Can't bind socket"); close(data_sk); close(ctrl_sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; bacpy(&addr.l2_bdaddr, dst); addr.l2_psm = htobs(data_psm); if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("ERROR: Can't connect to device"); close(data_sk); close(ctrl_sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } fputs("STATE: -connecting-to-device\n", stderr); memset(&opts, 0, sizeof(opts)); size = sizeof(opts); if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) { perror("ERROR: Can't get socket options"); close(data_sk); close(ctrl_sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } mtu = opts.omtu; /* Ignore SIGTERM signals if printing from stdin */ if (fd == 0) { #ifdef HAVE_SIGSET sigset(SIGTERM, SIG_IGN); #elif defined(HAVE_SIGACTION) memset(&action, 0, sizeof(action)); sigemptyset(&action.sa_mask); action.sa_handler = SIG_IGN; sigaction(SIGTERM, &action, NULL); #else signal(SIGTERM, SIG_IGN); #endif /* HAVE_SIGSET */ } tid = hcrp_get_next_tid(tid); if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) { fprintf(stderr, "ERROR: Can't grant initial credits\n"); close(data_sk); close(ctrl_sk); if (cups_class) return CUPS_BACKEND_FAILED; else return CUPS_BACKEND_RETRY; } for (i = 0; i < copies; i++) { if (fd != 0) { fprintf(stderr, "PAGE: 1 1\n"); lseek(fd, 0, SEEK_SET); } while (1) { if (credit < mtu) { tid = hcrp_get_next_tid(tid); if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) { credit += tmp; timeout = 0; } } if (!credit) { if (timeout++ > 300) { tid = hcrp_get_next_tid(tid); if (!hcrp_get_lpt_status(ctrl_sk, tid, &status)) fprintf(stderr, "ERROR: LPT status 0x%02x\n", status); break; } sleep(1); continue; } count = read(fd, buf, (credit > mtu) ? mtu : credit); if (count <= 0) break; len = write(data_sk, buf, count); if (len < 0) { perror("ERROR: Error writing to device"); close(data_sk); close(ctrl_sk); return CUPS_BACKEND_FAILED; } if (len != count) fprintf(stderr, "ERROR: Can't send complete data\n"); credit -= len; } } close(data_sk); close(ctrl_sk); return CUPS_BACKEND_OK; } bluez-4.101/cups/sdp.c0000644000000000000000000000551111376221745011445 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "cups.h" int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm) { sdp_list_t *srch, *attrs, *rsp; uuid_t svclass; uint16_t attr1, attr2; int err; if (!sdp) return -1; sdp_uuid16_create(&svclass, HCR_PRINT_SVCLASS_ID); srch = sdp_list_append(NULL, &svclass); attr1 = SDP_ATTR_PROTO_DESC_LIST; attrs = sdp_list_append(NULL, &attr1); attr2 = SDP_ATTR_ADD_PROTO_DESC_LIST; attrs = sdp_list_append(attrs, &attr2); err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp); if (err) return -1; for (; rsp; rsp = rsp->next) { sdp_record_t *rec = (sdp_record_t *) rsp->data; sdp_list_t *protos; if (!sdp_get_access_protos(rec, &protos)) { unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID); if (psm > 0) { *ctrl_psm = psm; } } if (!sdp_get_add_access_protos(rec, &protos)) { unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID); if (psm > 0 && *ctrl_psm > 0) { *data_psm = psm; return 0; } } } return -1; } int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel) { sdp_list_t *srch, *attrs, *rsp; uuid_t svclass; uint16_t attr; int err; if (!sdp) return -1; sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID); srch = sdp_list_append(NULL, &svclass); attr = SDP_ATTR_PROTO_DESC_LIST; attrs = sdp_list_append(NULL, &attr); err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp); if (err) return -1; for (; rsp; rsp = rsp->next) { sdp_record_t *rec = (sdp_record_t *) rsp->data; sdp_list_t *protos; if (!sdp_get_access_protos(rec, &protos)) { uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID); if (ch > 0) { *channel = ch; return 0; } } } return -1; } bluez-4.101/cups/main.c0000644000000000000000000005131611766125764011616 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cups.h" struct cups_device { char *bdaddr; char *name; char *id; }; static GSList *device_list = NULL; static GMainLoop *loop = NULL; static DBusConnection *conn = NULL; static gboolean doing_disco = FALSE; #define ATTRID_1284ID 0x0300 struct context_data { gboolean found; char *id; }; static void element_start(GMarkupParseContext *context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **err) { struct context_data *ctx_data = user_data; if (!strcmp(element_name, "record")) return; if (!strcmp(element_name, "attribute")) { int i; for (i = 0; attribute_names[i]; i++) { if (strcmp(attribute_names[i], "id") != 0) continue; if (strtol(attribute_values[i], 0, 0) == ATTRID_1284ID) ctx_data->found = TRUE; break; } return; } if (ctx_data->found && !strcmp(element_name, "text")) { int i; for (i = 0; attribute_names[i]; i++) { if (!strcmp(attribute_names[i], "value")) { ctx_data->id = g_strdup(attribute_values[i] + 2); ctx_data->found = FALSE; } } } } static GMarkupParser parser = { element_start, NULL, NULL, NULL, NULL }; static char *sdp_xml_parse_record(const char *data) { GMarkupParseContext *ctx; struct context_data ctx_data; int size; size = strlen(data); ctx_data.found = FALSE; ctx_data.id = NULL; ctx = g_markup_parse_context_new(&parser, 0, &ctx_data, NULL); if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) { g_markup_parse_context_free(ctx); g_free(ctx_data.id); return NULL; } g_markup_parse_context_free(ctx); return ctx_data.id; } static char *device_get_ieee1284_id(const char *adapter, const char *device) { DBusMessage *message, *reply; DBusMessageIter iter, reply_iter; DBusMessageIter reply_iter_entry; const char *hcr_print = "00001126-0000-1000-8000-00805f9b34fb"; const char *xml; char *id = NULL; /* Look for the service handle of the HCRP service */ message = dbus_message_new_method_call("org.bluez", device, "org.bluez.Device", "DiscoverServices"); dbus_message_iter_init_append(message, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print); reply = dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); if (!reply) return NULL; dbus_message_iter_init(reply, &reply_iter); if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { dbus_message_unref(reply); return NULL; } dbus_message_iter_recurse(&reply_iter, &reply_iter_entry); /* Hopefully we only get one handle, or take a punt */ while (dbus_message_iter_get_arg_type(&reply_iter_entry) == DBUS_TYPE_DICT_ENTRY) { guint32 key; DBusMessageIter dict_entry; dbus_message_iter_recurse(&reply_iter_entry, &dict_entry); /* Key ? */ dbus_message_iter_get_basic(&dict_entry, &key); if (!key) { dbus_message_iter_next(&reply_iter_entry); continue; } /* Try to get the value */ if (!dbus_message_iter_next(&dict_entry)) { dbus_message_iter_next(&reply_iter_entry); continue; } dbus_message_iter_get_basic(&dict_entry, &xml); id = sdp_xml_parse_record(xml); if (id != NULL) break; dbus_message_iter_next(&reply_iter_entry); } dbus_message_unref(reply); return id; } static void print_printer_details(const char *name, const char *bdaddr, const char *id) { char *uri, *escaped; escaped = g_strdelimit(g_strdup(name), "\"", '\''); uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c", bdaddr[0], bdaddr[1], bdaddr[3], bdaddr[4], bdaddr[6], bdaddr[7], bdaddr[9], bdaddr[10], bdaddr[12], bdaddr[13], bdaddr[15], bdaddr[16]); printf("direct %s \"%s\" \"%s (Bluetooth)\"", uri, escaped, escaped); if (id != NULL) printf(" \"%s\"\n", id); else printf("\n"); g_free(escaped); g_free(uri); } static void add_device_to_list(const char *name, const char *bdaddr, const char *id) { struct cups_device *device; GSList *l; /* Look for the device in the list */ for (l = device_list; l != NULL; l = l->next) { device = (struct cups_device *) l->data; if (strcmp(device->bdaddr, bdaddr) == 0) { if (device->name != name) { g_free(device->name); device->name = g_strdup(name); } g_free(device->id); device->id = g_strdup(id); return; } } /* Or add it to the list if it's not there */ device = g_new0(struct cups_device, 1); device->bdaddr = g_strdup(bdaddr); device->name = g_strdup(name); device->id = g_strdup(id); device_list = g_slist_prepend(device_list, device); print_printer_details(device->name, device->bdaddr, device->id); } static gboolean parse_device_properties(DBusMessageIter *reply_iter, char **name, char **bdaddr) { guint32 class = 0; DBusMessageIter reply_iter_entry; if (dbus_message_iter_get_arg_type(reply_iter) != DBUS_TYPE_ARRAY) return FALSE; dbus_message_iter_recurse(reply_iter, &reply_iter_entry); while (dbus_message_iter_get_arg_type(&reply_iter_entry) == DBUS_TYPE_DICT_ENTRY) { const char *key; DBusMessageIter dict_entry, iter_dict_val; dbus_message_iter_recurse(&reply_iter_entry, &dict_entry); /* Key == Class ? */ dbus_message_iter_get_basic(&dict_entry, &key); if (!key) { dbus_message_iter_next(&reply_iter_entry); continue; } if (strcmp(key, "Class") != 0 && strcmp(key, "Alias") != 0 && strcmp(key, "Address") != 0) { dbus_message_iter_next(&reply_iter_entry); continue; } /* Try to get the value */ if (!dbus_message_iter_next(&dict_entry)) { dbus_message_iter_next(&reply_iter_entry); continue; } dbus_message_iter_recurse(&dict_entry, &iter_dict_val); if (strcmp(key, "Class") == 0) { dbus_message_iter_get_basic(&iter_dict_val, &class); } else { const char *value; dbus_message_iter_get_basic(&iter_dict_val, &value); if (strcmp(key, "Alias") == 0) { *name = g_strdup(value); } else if (bdaddr) { *bdaddr = g_strdup(value); } } dbus_message_iter_next(&reply_iter_entry); } if (class == 0) return FALSE; if (((class & 0x1f00) >> 8) == 0x06 && (class & 0x80)) return TRUE; return FALSE; } static gboolean device_is_printer(const char *adapter, const char *device_path, char **name, char **bdaddr) { DBusMessage *message, *reply; DBusMessageIter reply_iter; gboolean retval; message = dbus_message_new_method_call("org.bluez", device_path, "org.bluez.Device", "GetProperties"); reply = dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); if (!reply) return FALSE; dbus_message_iter_init(reply, &reply_iter); retval = parse_device_properties(&reply_iter, name, bdaddr); dbus_message_unref(reply); return retval; } static void remote_device_found(const char *adapter, const char *bdaddr, const char *name) { DBusMessage *message, *reply, *adapter_reply; DBusMessageIter iter; char *object_path = NULL; char *id; adapter_reply = NULL; if (adapter == NULL) { message = dbus_message_new_method_call("org.bluez", "/", "org.bluez.Manager", "DefaultAdapter"); adapter_reply = dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); if (!adapter_reply) return; if (dbus_message_get_args(adapter_reply, NULL, DBUS_TYPE_OBJECT_PATH, &adapter, DBUS_TYPE_INVALID) == FALSE) { dbus_message_unref(adapter_reply); return; } } message = dbus_message_new_method_call("org.bluez", adapter, "org.bluez.Adapter", "FindDevice"); dbus_message_iter_init_append(message, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); if (adapter_reply != NULL) dbus_message_unref(adapter_reply); reply = dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); if (!reply) { message = dbus_message_new_method_call("org.bluez", adapter, "org.bluez.Adapter", "CreateDevice"); dbus_message_iter_init_append(message, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); reply = dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); if (!reply) return; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID) == FALSE) { dbus_message_unref(reply); return; } id = device_get_ieee1284_id(adapter, object_path); add_device_to_list(name, bdaddr, id); g_free(id); dbus_message_unref(reply); } static void discovery_completed(void) { g_slist_free(device_list); device_list = NULL; g_main_loop_quit(loop); } static void remote_device_disappeared(const char *bdaddr) { GSList *l; for (l = device_list; l != NULL; l = l->next) { struct cups_device *device = l->data; if (strcmp(device->bdaddr, bdaddr) == 0) { g_free(device->name); g_free(device->bdaddr); g_free(device); device_list = g_slist_delete_link(device_list, l); return; } } } static gboolean list_known_printers(const char *adapter) { DBusMessageIter reply_iter, iter_array; DBusError error; DBusMessage *message, *reply; message = dbus_message_new_method_call("org.bluez", adapter, "org.bluez.Adapter", "ListDevices"); if (message == NULL) return FALSE; dbus_error_init(&error); reply = dbus_connection_send_with_reply_and_block(conn, message, -1, &error); dbus_message_unref(message); if (dbus_error_is_set(&error)) return FALSE; dbus_message_iter_init(reply, &reply_iter); if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { dbus_message_unref(reply); return FALSE; } dbus_message_iter_recurse(&reply_iter, &iter_array); while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_OBJECT_PATH) { const char *object_path; char *name = NULL; char *bdaddr = NULL; dbus_message_iter_get_basic(&iter_array, &object_path); if (device_is_printer(adapter, object_path, &name, &bdaddr)) { char *id; id = device_get_ieee1284_id(adapter, object_path); add_device_to_list(name, bdaddr, id); g_free(id); } g_free(name); g_free(bdaddr); dbus_message_iter_next(&iter_array); } dbus_message_unref(reply); return FALSE; } static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *user_data) { if (dbus_message_is_signal(message, "org.bluez.Adapter", "DeviceFound")) { const char *adapter, *bdaddr; char *name; DBusMessageIter iter; dbus_message_iter_init(message, &iter); dbus_message_iter_get_basic(&iter, &bdaddr); dbus_message_iter_next(&iter); adapter = dbus_message_get_path(message); if (parse_device_properties(&iter, &name, NULL)) remote_device_found(adapter, bdaddr, name); g_free (name); } else if (dbus_message_is_signal(message, "org.bluez.Adapter", "DeviceDisappeared")) { const char *bdaddr; dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &bdaddr, DBUS_TYPE_INVALID); remote_device_disappeared(bdaddr); } else if (dbus_message_is_signal(message, "org.bluez.Adapter", "PropertyChanged")) { DBusMessageIter iter, value_iter; const char *name; gboolean discovering; dbus_message_iter_init(message, &iter); dbus_message_iter_get_basic(&iter, &name); if (name == NULL || strcmp(name, "Discovering") != 0) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &value_iter); dbus_message_iter_get_basic(&value_iter, &discovering); if (discovering == FALSE && doing_disco) { doing_disco = FALSE; discovery_completed(); } } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static gboolean list_printers(void) { /* 1. Connect to the bus * 2. Get the manager * 3. Get the default adapter * 4. Get a list of devices * 5. Get the class of each device * 6. Print the details from each printer device */ DBusError error; dbus_bool_t hcid_exists; DBusMessage *reply, *message; DBusMessageIter reply_iter; char *adapter, *match; conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL); if (conn == NULL) return TRUE; dbus_error_init(&error); hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error); if (dbus_error_is_set(&error)) return TRUE; if (!hcid_exists) return TRUE; /* Get the default adapter */ message = dbus_message_new_method_call("org.bluez", "/", "org.bluez.Manager", "DefaultAdapter"); if (message == NULL) { dbus_connection_unref(conn); return FALSE; } reply = dbus_connection_send_with_reply_and_block(conn, message, -1, &error); dbus_message_unref(message); if (dbus_error_is_set(&error)) { dbus_connection_unref(conn); /* No adapter */ return TRUE; } dbus_message_iter_init(reply, &reply_iter); if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_OBJECT_PATH) { dbus_message_unref(reply); dbus_connection_unref(conn); return FALSE; } dbus_message_iter_get_basic(&reply_iter, &adapter); adapter = g_strdup(adapter); dbus_message_unref(reply); if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) { g_free(adapter); dbus_connection_unref(conn); return FALSE; } #define MATCH_FORMAT \ "type='signal'," \ "interface='org.bluez.Adapter'," \ "sender='org.bluez'," \ "path='%s'" match = g_strdup_printf(MATCH_FORMAT, adapter); dbus_bus_add_match(conn, match, &error); g_free(match); /* Add the the recent devices */ list_known_printers(adapter); doing_disco = TRUE; message = dbus_message_new_method_call("org.bluez", adapter, "org.bluez.Adapter", "StartDiscovery"); if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) { dbus_message_unref(message); dbus_connection_unref(conn); g_free(adapter); return FALSE; } dbus_message_unref(message); loop = g_main_loop_new(NULL, TRUE); g_main_loop_run(loop); g_free(adapter); dbus_connection_unref(conn); return TRUE; } static gboolean print_ieee1284(const char *bdaddr) { DBusMessage *message, *reply, *adapter_reply; DBusMessageIter iter; char *object_path = NULL; char *adapter; char *id; adapter_reply = NULL; conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL); if (conn == NULL) return FALSE; message = dbus_message_new_method_call("org.bluez", "/", "org.bluez.Manager", "DefaultAdapter"); adapter_reply = dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); if (!adapter_reply) return FALSE; if (dbus_message_get_args(adapter_reply, NULL, DBUS_TYPE_OBJECT_PATH, &adapter, DBUS_TYPE_INVALID) == FALSE) { dbus_message_unref(adapter_reply); return FALSE; } message = dbus_message_new_method_call("org.bluez", adapter, "org.bluez.Adapter", "FindDevice"); dbus_message_iter_init_append(message, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); if (adapter_reply != NULL) dbus_message_unref(adapter_reply); reply = dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); if (!reply) { message = dbus_message_new_method_call("org.bluez", adapter, "org.bluez.Adapter", "CreateDevice"); dbus_message_iter_init_append(message, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); reply = dbus_connection_send_with_reply_and_block(conn, message, -1, NULL); dbus_message_unref(message); if (!reply) return FALSE; } if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_INVALID) == FALSE) { dbus_message_unref(reply); return FALSE; } id = device_get_ieee1284_id(adapter, object_path); if (id == NULL) { dbus_message_unref(reply); return FALSE; } printf("%s", id); g_free(id); dbus_message_unref(reply); return TRUE; } /* * Usage: printer-uri job-id user title copies options [file] * */ int main(int argc, char *argv[]) { sdp_session_t *sdp; bdaddr_t bdaddr; unsigned short ctrl_psm, data_psm; uint8_t channel, b[6]; char *ptr, str[3], device[18], service[12]; const char *uri, *cups_class; int i, err, fd, copies, proto; /* Make sure status messages are not buffered */ setbuf(stderr, NULL); /* Make sure output is not buffered */ setbuf(stdout, NULL); /* Ignore SIGPIPE signals */ #ifdef HAVE_SIGSET sigset(SIGPIPE, SIG_IGN); #elif defined(HAVE_SIGACTION) memset(&action, 0, sizeof(action)); action.sa_handler = SIG_IGN; sigaction(SIGPIPE, &action, NULL); #else signal(SIGPIPE, SIG_IGN); #endif /* HAVE_SIGSET */ if (argc == 1) { if (list_printers() == TRUE) return CUPS_BACKEND_OK; else return CUPS_BACKEND_FAILED; } else if (argc == 3 && strcmp(argv[1], "--get-deviceid") == 0) { if (bachk(argv[2]) < 0) { fprintf(stderr, "Invalid Bluetooth address '%s'\n", argv[2]); return CUPS_BACKEND_FAILED; } if (print_ieee1284(argv[2]) == FALSE) return CUPS_BACKEND_FAILED; return CUPS_BACKEND_OK; } if (argc < 6 || argc > 7) { fprintf(stderr, "Usage: bluetooth job-id user title copies" " options [file]\n"); fprintf(stderr, " bluetooth --get-deviceid [bdaddr]\n"); return CUPS_BACKEND_FAILED; } if (argc == 6) { fd = 0; copies = 1; } else { if ((fd = open(argv[6], O_RDONLY)) < 0) { perror("ERROR: Unable to open print file"); return CUPS_BACKEND_FAILED; } copies = atoi(argv[4]); } uri = getenv("DEVICE_URI"); if (!uri) uri = argv[0]; if (strncasecmp(uri, "bluetooth://", 12)) { fprintf(stderr, "ERROR: No device URI found\n"); return CUPS_BACKEND_FAILED; } ptr = argv[0] + 12; for (i = 0; i < 6; i++) { strncpy(str, ptr, 2); b[i] = (uint8_t) strtol(str, NULL, 16); ptr += 2; } sprintf(device, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", b[0], b[1], b[2], b[3], b[4], b[5]); str2ba(device, &bdaddr); ptr = strchr(ptr, '/'); if (ptr) { strncpy(service, ptr + 1, 12); if (!strncasecmp(ptr + 1, "spp", 3)) proto = 1; else if (!strncasecmp(ptr + 1, "hcrp", 4)) proto = 2; else proto = 0; } else { strcpy(service, "auto"); proto = 0; } cups_class = getenv("CLASS"); fprintf(stderr, "DEBUG: %s device %s service %s fd %d copies %d class %s\n", argv[0], device, service, fd, copies, cups_class ? cups_class : "(none)"); fputs("STATE: +connecting-to-device\n", stderr); service_search: sdp = sdp_connect(BDADDR_ANY, &bdaddr, SDP_RETRY_IF_BUSY); if (!sdp) { fprintf(stderr, "ERROR: Can't open Bluetooth connection\n"); return CUPS_BACKEND_FAILED; } switch (proto) { case 1: err = sdp_search_spp(sdp, &channel); break; case 2: err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm); break; default: proto = 2; err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm); if (err) { proto = 1; err = sdp_search_spp(sdp, &channel); } break; } sdp_close(sdp); if (err) { if (cups_class) { fputs("INFO: Unable to contact printer, queuing on " "next printer in class...\n", stderr); sleep(5); return CUPS_BACKEND_FAILED; } sleep(20); fprintf(stderr, "ERROR: Can't get service information\n"); goto service_search; } connect: switch (proto) { case 1: err = spp_print(BDADDR_ANY, &bdaddr, channel, fd, copies, cups_class); break; case 2: err = hcrp_print(BDADDR_ANY, &bdaddr, ctrl_psm, data_psm, fd, copies, cups_class); break; default: err = CUPS_BACKEND_FAILED; fprintf(stderr, "ERROR: Unsupported protocol\n"); break; } if (err == CUPS_BACKEND_FAILED && cups_class) { fputs("INFO: Unable to contact printer, queuing on " "next printer in class...\n", stderr); sleep(5); return CUPS_BACKEND_FAILED; } else if (err == CUPS_BACKEND_RETRY) { sleep(20); goto connect; } if (fd != 0) close(fd); if (!err) fprintf(stderr, "INFO: Ready to print\n"); return err; } bluez-4.101/proximity/0000755000000000000000000000000011771120005011645 500000000000000bluez-4.101/proximity/monitor.c0000644000000000000000000004226711766125764013460 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "dbus-common.h" #include "adapter.h" #include "device.h" #include "error.h" #include "log.h" #include "att.h" #include "gattrib.h" #include "gatt.h" #include "attio.h" #include "monitor.h" #include "textfile.h" #define PROXIMITY_INTERFACE "org.bluez.ProximityMonitor" #define ALERT_LEVEL_CHR_UUID 0x2A06 #define POWER_LEVEL_CHR_UUID 0x2A07 #define IMMEDIATE_TIMEOUT 5 enum { ALERT_NONE = 0, ALERT_MILD, ALERT_HIGH, }; struct monitor { struct btd_device *device; GAttrib *attrib; DBusConnection *conn; struct att_range *linkloss; struct att_range *txpower; struct att_range *immediate; struct enabled enabled; char *linklosslevel; /* Link Loss Alert Level */ char *fallbacklevel; /* Immediate fallback alert level */ char *immediatelevel; /* Immediate Alert Level */ char *signallevel; /* Path Loss RSSI level */ uint16_t linklosshandle; /* Link Loss Characteristic * Value Handle */ uint16_t txpowerhandle; /* Tx Characteristic Value Handle */ uint16_t immediatehandle; /* Immediate Alert Value Handle */ guint immediateto; /* Reset Immediate Alert to "none" */ guint attioid; }; static inline int create_filename(char *buf, size_t size, const bdaddr_t *bdaddr, const char *name) { char addr[18]; ba2str(bdaddr, addr); return create_name(buf, size, STORAGEDIR, addr, name); } static int write_proximity_config(bdaddr_t *sba, bdaddr_t *dba, const char *alert, const char *level) { char filename[PATH_MAX + 1], addr[18], key[38]; create_filename(filename, PATH_MAX, sba, "proximity"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(dba, addr); snprintf(key, sizeof(key), "%17s#%s", addr, alert); return textfile_put(filename, key, level); } static char *read_proximity_config(bdaddr_t *sba, bdaddr_t *dba, const char *alert) { char filename[PATH_MAX + 1], addr[18], key[38]; char *str, *strnew; create_filename(filename, PATH_MAX, sba, "proximity"); ba2str(dba, addr); snprintf(key, sizeof(key), "%17s#%s", addr, alert); str = textfile_caseget(filename, key); if (str == NULL) return NULL; strnew = g_strdup(str); free(str); return strnew; } static uint8_t str2level(const char *level) { if (g_strcmp0("high", level) == 0) return ALERT_HIGH; else if (g_strcmp0("mild", level) == 0) return ALERT_MILD; return ALERT_NONE; } static void linkloss_written(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct monitor *monitor = user_data; struct btd_device *device = monitor->device; const char *path = device_get_path(device); if (status != 0) { error("Link Loss Write Request failed: %s", att_ecode2str(status)); return; } if (!dec_write_resp(pdu, plen)) { error("Link Loss Write Request: protocol error"); return; } DBG("Link Loss Alert Level written"); emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE, "LinkLossAlertLevel", DBUS_TYPE_STRING, &monitor->linklosslevel); } static void char_discovered_cb(GSList *characteristics, guint8 status, gpointer user_data) { struct monitor *monitor = user_data; struct gatt_char *chr; uint8_t value = str2level(monitor->linklosslevel); if (status) { error("Discover Link Loss handle: %s", att_ecode2str(status)); return; } DBG("Setting alert level \"%s\" on Reporter", monitor->linklosslevel); /* Assume there is a single Alert Level characteristic */ chr = characteristics->data; monitor->linklosshandle = chr->value_handle; gatt_write_char(monitor->attrib, monitor->linklosshandle, &value, 1, linkloss_written, monitor); } static int write_alert_level(struct monitor *monitor) { struct att_range *linkloss = monitor->linkloss; bt_uuid_t uuid; if (monitor->linklosshandle) { uint8_t value = str2level(monitor->linklosslevel); gatt_write_char(monitor->attrib, monitor->linklosshandle, &value, 1, linkloss_written, monitor); return 0; } bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID); /* FIXME: use cache (requires service changed support) ? */ gatt_discover_char(monitor->attrib, linkloss->start, linkloss->end, &uuid, char_discovered_cb, monitor); return 0; } static void tx_power_read_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { uint8_t value[ATT_MAX_MTU]; int vlen; if (status != 0) { DBG("Tx Power Level read failed: %s", att_ecode2str(status)); return; } if (!dec_read_resp(pdu, plen, value, &vlen)) { DBG("Protocol error"); return; } if (vlen != 1) { DBG("Invalid length for TX Power value: %d", vlen); return; } DBG("Tx Power Level: %02x", (int8_t) value[0]); } static void tx_power_handle_cb(GSList *characteristics, guint8 status, gpointer user_data) { struct monitor *monitor = user_data; struct gatt_char *chr; if (status) { error("Discover Tx Power handle: %s", att_ecode2str(status)); return; } chr = characteristics->data; monitor->txpowerhandle = chr->value_handle; DBG("Tx Power handle: 0x%04x", monitor->txpowerhandle); gatt_read_char(monitor->attrib, monitor->txpowerhandle, 0, tx_power_read_cb, monitor); } static void read_tx_power(struct monitor *monitor) { struct att_range *txpower = monitor->txpower; bt_uuid_t uuid; if (monitor->txpowerhandle != 0) { gatt_read_char(monitor->attrib, monitor->txpowerhandle, 0, tx_power_read_cb, monitor); return; } bt_uuid16_create(&uuid, POWER_LEVEL_CHR_UUID); gatt_discover_char(monitor->attrib, txpower->start, txpower->end, &uuid, tx_power_handle_cb, monitor); } static gboolean immediate_timeout(gpointer user_data) { struct monitor *monitor = user_data; const char *path = device_get_path(monitor->device); monitor->immediateto = 0; if (g_strcmp0(monitor->immediatelevel, "none") == 0) return FALSE; if (monitor->attrib) { uint8_t value = ALERT_NONE; gatt_write_cmd(monitor->attrib, monitor->immediatehandle, &value, 1, NULL, NULL); } g_free(monitor->immediatelevel); monitor->immediatelevel = g_strdup("none"); emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE, "ImmediateAlertLevel", DBUS_TYPE_STRING, &monitor->immediatelevel); return FALSE; } static void immediate_written(gpointer user_data) { struct monitor *monitor = user_data; const char *path = device_get_path(monitor->device); g_free(monitor->fallbacklevel); monitor->fallbacklevel = NULL; emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE, "ImmediateAlertLevel", DBUS_TYPE_STRING, &monitor->immediatelevel); monitor->immediateto = g_timeout_add_seconds(IMMEDIATE_TIMEOUT, immediate_timeout, monitor); } static void write_immediate_alert(struct monitor *monitor) { uint8_t value = str2level(monitor->immediatelevel); gatt_write_cmd(monitor->attrib, monitor->immediatehandle, &value, 1, immediate_written, monitor); } static void immediate_handle_cb(GSList *characteristics, guint8 status, gpointer user_data) { struct monitor *monitor = user_data; struct gatt_char *chr; if (status) { error("Discover Immediate Alert handle: %s", att_ecode2str(status)); return; } chr = characteristics->data; monitor->immediatehandle = chr->value_handle; DBG("Immediate Alert handle: 0x%04x", monitor->immediatehandle); if (monitor->fallbacklevel) write_immediate_alert(monitor); } static void discover_immediate_handle(struct monitor *monitor) { struct att_range *immediate = monitor->immediate; bt_uuid_t uuid; bt_uuid16_create(&uuid, ALERT_LEVEL_CHR_UUID); gatt_discover_char(monitor->attrib, immediate->start, immediate->end, &uuid, immediate_handle_cb, monitor); } static void attio_connected_cb(GAttrib *attrib, gpointer user_data) { struct monitor *monitor = user_data; monitor->attrib = g_attrib_ref(attrib); if (monitor->enabled.linkloss) write_alert_level(monitor); if (monitor->enabled.pathloss) read_tx_power(monitor); if (monitor->immediatehandle == 0) { if(monitor->enabled.pathloss || monitor->enabled.findme) discover_immediate_handle(monitor); } else if (monitor->fallbacklevel) write_immediate_alert(monitor); } static void attio_disconnected_cb(gpointer user_data) { struct monitor *monitor = user_data; const char *path = device_get_path(monitor->device); g_attrib_unref(monitor->attrib); monitor->attrib = NULL; if (monitor->immediateto == 0) return; g_source_remove(monitor->immediateto); monitor->immediateto = 0; if (g_strcmp0(monitor->immediatelevel, "none") == 0) return; g_free(monitor->immediatelevel); monitor->immediatelevel = g_strdup("none"); emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE, "ImmediateAlertLevel", DBUS_TYPE_STRING, &monitor->immediatelevel); } static gboolean level_is_valid(const char *level) { return (g_str_equal("none", level) || g_str_equal("mild", level) || g_str_equal("high", level)); } static DBusMessage *set_link_loss_alert(DBusConnection *conn, DBusMessage *msg, const char *level, void *data) { struct monitor *monitor = data; struct btd_device *device = monitor->device; bdaddr_t sba, dba; if (!level_is_valid(level)) return btd_error_invalid_args(msg); if (g_strcmp0(monitor->linklosslevel, level) == 0) return dbus_message_new_method_return(msg); g_free(monitor->linklosslevel); monitor->linklosslevel = g_strdup(level); adapter_get_address(device_get_adapter(device), &sba); device_get_address(device, &dba, NULL); write_proximity_config(&sba, &dba, "LinkLossAlertLevel", level); if (monitor->attrib) write_alert_level(monitor); return dbus_message_new_method_return(msg); } static DBusMessage *set_immediate_alert(DBusConnection *conn, DBusMessage *msg, const char *level, void *data) { struct monitor *monitor = data; if (!level_is_valid(level)) return btd_error_invalid_args(msg); if (g_strcmp0(monitor->immediatelevel, level) == 0) return dbus_message_new_method_return(msg); if (monitor->immediateto) { g_source_remove(monitor->immediateto); monitor->immediateto = 0; } /* Previous Immediate Alert level if connection/write fails */ g_free(monitor->fallbacklevel); monitor->fallbacklevel = monitor->immediatelevel; monitor->immediatelevel = g_strdup(level); /* * Means that Link/Path Loss are disabled or there is a pending * writting for Find Me(Immediate Alert characteristic value). * If enabled, Path Loss always registers a connection callback * when the Proximity Monitor starts. */ if (monitor->attioid == 0) monitor->attioid = btd_device_add_attio_callback(monitor->device, attio_connected_cb, attio_disconnected_cb, monitor); else if (monitor->attrib) write_immediate_alert(monitor); return dbus_message_new_method_return(msg); } static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct monitor *monitor = data; DBusMessageIter iter; DBusMessageIter dict; DBusMessage *reply; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); if (monitor->enabled.linkloss) dict_append_entry(&dict, "LinkLossAlertLevel", DBUS_TYPE_STRING, &monitor->linklosslevel); if (monitor->enabled.findme || monitor->enabled.pathloss) dict_append_entry(&dict, "ImmediateAlertLevel", DBUS_TYPE_STRING, &monitor->immediatelevel); if (monitor->enabled.pathloss) dict_append_entry(&dict, "SignalLevel", DBUS_TYPE_STRING, &monitor->signallevel); dbus_message_iter_close_container(&iter, &dict); return reply; } static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, void *data) { struct monitor *monitor = data; const char *property; DBusMessageIter iter; DBusMessageIter sub; const char *level; if (!dbus_message_iter_init(msg, &iter)) return btd_error_invalid_args(msg); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return btd_error_invalid_args(msg); dbus_message_iter_recurse(&iter, &sub); if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &level); if (g_str_equal("ImmediateAlertLevel", property)) { if (monitor->enabled.findme == FALSE && monitor->enabled.pathloss == FALSE) return btd_error_not_available(msg); return set_immediate_alert(conn, msg, level, data); } else if (g_str_equal("LinkLossAlertLevel", property)) { if (monitor->enabled.linkloss == FALSE) return btd_error_not_available(msg); return set_link_loss_alert(conn, msg, level, data); } return btd_error_invalid_args(msg); } static const GDBusMethodTable monitor_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), get_properties) }, { GDBUS_ASYNC_METHOD("SetProperty", GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL, set_property) }, { } }; static const GDBusSignalTable monitor_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static void monitor_destroy(gpointer user_data) { struct monitor *monitor = user_data; if (monitor->immediateto) g_source_remove(monitor->immediateto); if (monitor->attioid) btd_device_remove_attio_callback(monitor->device, monitor->attioid); if (monitor->attrib) g_attrib_unref(monitor->attrib); dbus_connection_unref(monitor->conn); btd_device_unref(monitor->device); g_free(monitor->linkloss); g_free(monitor->immediate); g_free(monitor->txpower); g_free(monitor->linklosslevel); g_free(monitor->immediatelevel); g_free(monitor->signallevel); g_free(monitor); } int monitor_register(DBusConnection *conn, struct btd_device *device, struct gatt_primary *linkloss, struct gatt_primary *txpower, struct gatt_primary *immediate, struct enabled *enabled) { const char *path = device_get_path(device); struct monitor *monitor; bdaddr_t sba, dba; char *level; adapter_get_address(device_get_adapter(device), &sba); device_get_address(device, &dba, NULL); level = read_proximity_config(&sba, &dba, "LinkLossAlertLevel"); monitor = g_new0(struct monitor, 1); monitor->device = btd_device_ref(device); monitor->conn = dbus_connection_ref(conn); monitor->linklosslevel = (level ? : g_strdup("high")); monitor->signallevel = g_strdup("unknown"); monitor->immediatelevel = g_strdup("none"); if (g_dbus_register_interface(conn, path, PROXIMITY_INTERFACE, monitor_methods, monitor_signals, NULL, monitor, monitor_destroy) == FALSE) { error("D-Bus failed to register %s interface", PROXIMITY_INTERFACE); monitor_destroy(monitor); return -1; } DBG("Registered interface %s on path %s", PROXIMITY_INTERFACE, path); if (linkloss && enabled->linkloss) { monitor->linkloss = g_new0(struct att_range, 1); monitor->linkloss->start = linkloss->range.start; monitor->linkloss->end = linkloss->range.end; monitor->enabled.linkloss = TRUE; } if (immediate) { if (txpower && enabled->pathloss) { monitor->txpower = g_new0(struct att_range, 1); monitor->txpower->start = txpower->range.start; monitor->txpower->end = txpower->range.end; monitor->enabled.pathloss = TRUE; } if (enabled->pathloss || enabled->findme) { monitor->immediate = g_new0(struct att_range, 1); monitor->immediate->start = immediate->range.start; monitor->immediate->end = immediate->range.end; } monitor->enabled.findme = enabled->findme; } DBG("Link Loss: %s, Path Loss: %s, FindMe: %s", monitor->enabled.linkloss ? "TRUE" : "FALSE", monitor->enabled.pathloss ? "TRUE" : "FALSE", monitor->enabled.findme ? "TRUE" : "FALSE"); if (monitor->enabled.linkloss || monitor->enabled.pathloss) monitor->attioid = btd_device_add_attio_callback(device, attio_connected_cb, attio_disconnected_cb, monitor); return 0; } void monitor_unregister(DBusConnection *conn, struct btd_device *device) { const char *path = device_get_path(device); g_dbus_unregister_interface(conn, path, PROXIMITY_INTERFACE); } bluez-4.101/proximity/reporter.h0000644000000000000000000000253111766125764013626 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define PROXIMITY_REPORTER_INTERFACE "org.bluez.ProximityReporter" #define IMMEDIATE_ALERT_SVC_UUID 0x1802 #define LINK_LOSS_SVC_UUID 0x1803 #define TX_POWER_SVC_UUID 0x1804 #define ALERT_LEVEL_CHR_UUID 0x2A06 #define POWER_LEVEL_CHR_UUID 0x2A07 enum { NO_ALERT = 0x00, MILD_ALERT = 0x01, HIGH_ALERT = 0x02, }; int reporter_init(struct btd_adapter *adapter); void reporter_exit(struct btd_adapter *adapter); const char *get_alert_level_string(uint8_t level); bluez-4.101/proximity/proximity.conf0000644000000000000000000000040211766125764014521 00000000000000# Configuration file for the proximity service # This section contains options which are not specific to any # particular interface [General] # Configuration to allow disabling Proximity services # Allowed values: LinkLoss,PathLoss,FindMe Disable=PathLoss bluez-4.101/proximity/linkloss.c0000644000000000000000000002037411766125764013622 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "log.h" #include "att-database.h" #include "gattrib.h" #include "att.h" #include "gatt.h" #include "gatt-service.h" #include "attrib-server.h" #include "device.h" #include "attio.h" #include "dbus-common.h" #include "reporter.h" #include "linkloss.h" #define BLUEZ_SERVICE "org.bluez" struct link_loss_adapter { struct btd_adapter *adapter; uint16_t alert_lvl_value_handle; DBusConnection *conn; GSList *connected_devices; }; struct connected_device { struct btd_device *device; struct link_loss_adapter *adapter; uint8_t alert_level; guint callback_id; guint local_disc_id; }; static GSList *link_loss_adapters; static int lldevice_cmp(gconstpointer a, gconstpointer b) { const struct connected_device *llcondev = a; const struct btd_device *device = b; if (llcondev->device == device) return 0; return -1; } static struct connected_device * find_connected_device(struct link_loss_adapter *la, struct btd_device *device) { GSList *l = g_slist_find_custom(la->connected_devices, device, lldevice_cmp); if (!l) return NULL; return l->data; } static int lladapter_cmp(gconstpointer a, gconstpointer b) { const struct link_loss_adapter *lladapter = a; const struct btd_adapter *adapter = b; if (lladapter->adapter == adapter) return 0; return -1; } static struct link_loss_adapter * find_link_loss_adapter(struct btd_adapter *adapter) { GSList *l = g_slist_find_custom(link_loss_adapters, adapter, lladapter_cmp); if (!l) return NULL; return l->data; } const char *link_loss_get_alert_level(struct btd_device *device) { struct link_loss_adapter *lladapter; struct connected_device *condev; if (!device) return get_alert_level_string(NO_ALERT); lladapter = find_link_loss_adapter(device_get_adapter(device)); if (!lladapter) return get_alert_level_string(NO_ALERT); condev = find_connected_device(lladapter, device); if (!condev) return get_alert_level_string(NO_ALERT); return get_alert_level_string(condev->alert_level); } static void link_loss_emit_alert_signal(struct connected_device *condev) { struct link_loss_adapter *adapter = condev->adapter; const char *alert_level_str, *path; if (!condev->device) return; path = device_get_path(condev->device); alert_level_str = get_alert_level_string(condev->alert_level); DBG("alert %s remote %s", alert_level_str, path); emit_property_changed(adapter->conn, path, PROXIMITY_REPORTER_INTERFACE, "LinkLossAlertLevel", DBUS_TYPE_STRING, &alert_level_str); } static uint8_t link_loss_alert_lvl_read(struct attribute *a, struct btd_device *device, gpointer user_data) { struct link_loss_adapter *la = user_data; struct connected_device *condev; uint8_t alert_level = NO_ALERT; if (!device) goto out; condev = find_connected_device(la, device); if (!condev) goto out; alert_level = condev->alert_level; out: DBG("return alert level %d for dev %p", alert_level, device); /* update the alert level according to the requesting device */ attrib_db_update(la->adapter, a->handle, NULL, &alert_level, sizeof(alert_level), NULL); return 0; } /* condev can be NULL */ static void link_loss_remove_condev(struct connected_device *condev) { struct link_loss_adapter *la; if (!condev) return; la = condev->adapter; if (condev->callback_id && condev->device) btd_device_remove_attio_callback(condev->device, condev->callback_id); if (condev->local_disc_id && condev->device) device_remove_disconnect_watch(condev->device, condev->local_disc_id); if (condev->device) btd_device_unref(condev->device); la->connected_devices = g_slist_remove(la->connected_devices, condev); g_free(condev); } static void link_loss_disc_cb(gpointer user_data) { struct connected_device *condev = user_data; DBG("alert loss disconnect device %p", condev->device); /* if an alert-level is set, emit a signal */ if (condev->alert_level != NO_ALERT) link_loss_emit_alert_signal(condev); /* we are open for more changes now */ link_loss_remove_condev(condev); } static void link_loss_local_disc(struct btd_device *device, gboolean removal, void *user_data) { struct connected_device *condev = user_data; /* no need to alert on this device - we requested disconnection */ link_loss_remove_condev(condev); DBG("alert level zeroed for locally disconnecting dev %p", device); } static uint8_t link_loss_alert_lvl_write(struct attribute *a, struct btd_device *device, gpointer user_data) { uint8_t value; struct link_loss_adapter *la = user_data; struct connected_device *condev = NULL; if (!device) goto set_error; /* condev might remain NULL here if nothing is found */ condev = find_connected_device(la, device); if (a->len == 0) { DBG("Illegal alert level length"); goto set_error; } value = a->data[0]; if (value != NO_ALERT && value != MILD_ALERT && value != HIGH_ALERT) { DBG("Illegal alert value"); goto set_error; } /* Register a disconnect cb if the alert level is non-zero */ if (value != NO_ALERT && !condev) { condev = g_new0(struct connected_device, 1); condev->device = btd_device_ref(device); condev->adapter = la; condev->callback_id = btd_device_add_attio_callback(device, NULL, link_loss_disc_cb, condev); condev->local_disc_id = device_add_disconnect_watch(device, link_loss_local_disc, condev, NULL); la->connected_devices = g_slist_append(la->connected_devices, condev); } else if (value == NO_ALERT && condev) { link_loss_remove_condev(condev); condev = NULL; } DBG("alert level set to %d by device %p", value, device); if (condev) condev->alert_level = value; return 0; set_error: error("Set link loss alert level for dev %p", device); /* reset alert level on erroneous devices */ link_loss_remove_condev(condev); return ATT_ECODE_IO; } void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn) { gboolean svc_added; bt_uuid_t uuid; struct link_loss_adapter *lladapter; bt_uuid16_create(&uuid, LINK_LOSS_SVC_UUID); lladapter = g_new0(struct link_loss_adapter, 1); lladapter->adapter = adapter; lladapter->conn = dbus_connection_ref(conn); link_loss_adapters = g_slist_append(link_loss_adapters, lladapter); /* Link Loss Service */ svc_added = gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid, /* Alert level characteristic */ GATT_OPT_CHR_UUID, ALERT_LEVEL_CHR_UUID, GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_WRITE, GATT_OPT_CHR_VALUE_CB, ATTRIB_READ, link_loss_alert_lvl_read, lladapter, GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE, link_loss_alert_lvl_write, lladapter, GATT_OPT_CHR_VALUE_GET_HANDLE, &lladapter->alert_lvl_value_handle, GATT_OPT_INVALID); if (!svc_added) goto err; DBG("Link Loss service added"); return; err: error("Error adding Link Loss service"); link_loss_unregister(adapter); } static void remove_condev_list_item(gpointer data, gpointer user_data) { struct connected_device *condev = data; link_loss_remove_condev(condev); } void link_loss_unregister(struct btd_adapter *adapter) { struct link_loss_adapter *lladapter; lladapter = find_link_loss_adapter(adapter); if (!lladapter) return; g_slist_foreach(lladapter->connected_devices, remove_condev_list_item, NULL); dbus_connection_unref(lladapter->conn); link_loss_adapters = g_slist_remove(link_loss_adapters, lladapter); g_free(lladapter); } bluez-4.101/proximity/linkloss.h0000644000000000000000000000202711766125764013622 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments Corporation * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn); void link_loss_unregister(struct btd_adapter *adapter); const char *link_loss_get_alert_level(struct btd_device *device); bluez-4.101/proximity/reporter.c0000644000000000000000000001711211766125764013622 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "log.h" #include "dbus-common.h" #include "error.h" #include "device.h" #include "hcid.h" #include "gattrib.h" #include "att.h" #include "gatt.h" #include "att-database.h" #include "attrib-server.h" #include "reporter.h" #include "linkloss.h" #include "immalert.h" #define BLUEZ_SERVICE "org.bluez" struct reporter_adapter { DBusConnection *conn; struct btd_adapter *adapter; GSList *devices; }; static GSList *reporter_adapters; static int radapter_cmp(gconstpointer a, gconstpointer b) { const struct reporter_adapter *radapter = a; const struct btd_adapter *adapter = b; if (radapter->adapter == adapter) return 0; return -1; } static struct reporter_adapter * find_reporter_adapter(struct btd_adapter *adapter) { GSList *l = g_slist_find_custom(reporter_adapters, adapter, radapter_cmp); if (!l) return NULL; return l->data; } const char *get_alert_level_string(uint8_t level) { switch (level) { case NO_ALERT: return "none"; case MILD_ALERT: return "mild"; case HIGH_ALERT: return "high"; } return "unknown"; } static void register_tx_power(struct btd_adapter *adapter) { uint16_t start_handle, h; const int svc_size = 4; uint8_t atval[256]; bt_uuid_t uuid; bt_uuid16_create(&uuid, TX_POWER_SVC_UUID); start_handle = attrib_db_find_avail(adapter, &uuid, svc_size); if (start_handle == 0) { error("Not enough free handles to register service"); return; } DBG("start_handle=0x%04x", start_handle); h = start_handle; /* Primary service definition */ bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID); att_put_u16(TX_POWER_SVC_UUID, &atval[0]); attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2); /* Power level characteristic */ bt_uuid16_create(&uuid, GATT_CHARAC_UUID); atval[0] = ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_NOTIFY; att_put_u16(h + 1, &atval[1]); att_put_u16(POWER_LEVEL_CHR_UUID, &atval[3]); attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5); /* Power level value */ bt_uuid16_create(&uuid, POWER_LEVEL_CHR_UUID); att_put_u8(0x00, &atval[0]); attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 1); /* Client characteristic configuration */ bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID); atval[0] = 0x00; atval[1] = 0x00; attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NONE, atval, 2); g_assert(h - start_handle == svc_size); } static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter; DBusMessageIter dict; DBusMessage *reply = NULL; const char *linkloss_level, *immalert_level; struct btd_device *device = data; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; linkloss_level = link_loss_get_alert_level(device); immalert_level = imm_alert_get_level(device); dbus_message_iter_init_append(reply, &iter); if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict)) goto err; dict_append_entry(&dict, "LinkLossAlertLevel", DBUS_TYPE_STRING, &linkloss_level); dict_append_entry(&dict, "ImmediateAlertLevel", DBUS_TYPE_STRING, &immalert_level); if (!dbus_message_iter_close_container(&iter, &dict)) goto err; return reply; err: if (reply) dbus_message_unref(reply); return btd_error_failed(msg, "not enough memory"); } static const GDBusMethodTable reporter_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), get_properties) }, { } }; static const GDBusSignalTable reporter_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static void unregister_reporter_device(gpointer data, gpointer user_data) { struct btd_device *device = data; struct reporter_adapter *radapter = user_data; const char *path = device_get_path(device); DBG("unregister on device %s", path); g_dbus_unregister_interface(radapter->conn, path, PROXIMITY_REPORTER_INTERFACE); radapter->devices = g_slist_remove(radapter->devices, device); btd_device_unref(device); } static void register_reporter_device(struct btd_device *device, struct reporter_adapter *radapter) { const char *path = device_get_path(device); DBG("register on device %s", path); g_dbus_register_interface(radapter->conn, path, PROXIMITY_REPORTER_INTERFACE, reporter_methods, reporter_signals, NULL, device, NULL); btd_device_ref(device); radapter->devices = g_slist_prepend(radapter->devices, device); } static int reporter_device_probe(struct btd_device *device, GSList *uuids) { struct reporter_adapter *radapter; struct btd_adapter *adapter = device_get_adapter(device); radapter = find_reporter_adapter(adapter); if (!radapter) return -1; register_reporter_device(device, radapter); return 0; } static void reporter_device_remove(struct btd_device *device) { struct reporter_adapter *radapter; struct btd_adapter *adapter = device_get_adapter(device); radapter = find_reporter_adapter(adapter); if (!radapter) return; unregister_reporter_device(device, radapter); } /* device driver for tracking remote GATT client devices */ static struct btd_device_driver reporter_device_driver = { .name = "Proximity GATT Reporter Device Tracker Driver", .uuids = BTD_UUIDS(GATT_UUID), .probe = reporter_device_probe, .remove = reporter_device_remove, }; int reporter_init(struct btd_adapter *adapter) { struct reporter_adapter *radapter; DBusConnection *conn; if (!main_opts.gatt_enabled) { DBG("GATT is disabled"); return -ENOTSUP; } conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (!conn) return -1; radapter = g_new0(struct reporter_adapter, 1); radapter->adapter = adapter; radapter->conn = conn; link_loss_register(adapter, radapter->conn); register_tx_power(adapter); imm_alert_register(adapter, radapter->conn); btd_register_device_driver(&reporter_device_driver); reporter_adapters = g_slist_prepend(reporter_adapters, radapter); DBG("Proximity Reporter for adapter %p", adapter); return 0; } void reporter_exit(struct btd_adapter *adapter) { struct reporter_adapter *radapter = find_reporter_adapter(adapter); if (!radapter) return; btd_unregister_device_driver(&reporter_device_driver); g_slist_foreach(radapter->devices, unregister_reporter_device, radapter); link_loss_unregister(adapter); imm_alert_unregister(adapter); dbus_connection_unref(radapter->conn); reporter_adapters = g_slist_remove(reporter_adapters, radapter); g_free(radapter); } bluez-4.101/proximity/main.c0000644000000000000000000000430611766125764012705 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "log.h" #include "plugin.h" #include "manager.h" #include "hcid.h" static DBusConnection *connection = NULL; static GKeyFile *config = NULL; static GKeyFile *open_config_file(const char *file) { GError *gerr = NULL; GKeyFile *keyfile; keyfile = g_key_file_new(); g_key_file_set_list_separator(keyfile, ','); if (!g_key_file_load_from_file(keyfile, file, 0, &gerr)) { error("Parsing %s failed: %s", file, gerr->message); g_error_free(gerr); g_key_file_free(keyfile); return NULL; } return keyfile; } static int proximity_init(void) { if (!main_opts.gatt_enabled) { DBG("GATT is disabled"); return -ENOTSUP; } connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (connection == NULL) return -EIO; config = open_config_file(CONFIGDIR "/proximity.conf"); if (proximity_manager_init(connection, config) < 0) { dbus_connection_unref(connection); return -EIO; } return 0; } static void proximity_exit(void) { if (!main_opts.gatt_enabled) return; if (config) g_key_file_free(config); proximity_manager_exit(); dbus_connection_unref(connection); } BLUETOOTH_PLUGIN_DEFINE(proximity, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, proximity_init, proximity_exit) bluez-4.101/proximity/manager.h0000644000000000000000000000175011766125764013400 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int proximity_manager_init(DBusConnection *conn, GKeyFile *conf); void proximity_manager_exit(void); bluez-4.101/proximity/immalert.h0000644000000000000000000000202111766125764013570 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments Corporation * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn); void imm_alert_unregister(struct btd_adapter *adapter); const char *imm_alert_get_level(struct btd_device *device); bluez-4.101/proximity/manager.c0000644000000000000000000000722211766125764013373 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "adapter.h" #include "device.h" #include "att.h" #include "gattrib.h" #include "gatt.h" #include "monitor.h" #include "reporter.h" #include "manager.h" static DBusConnection *connection = NULL; static struct enabled enabled = { .linkloss = TRUE, .pathloss = TRUE, .findme = TRUE, }; static gint primary_uuid_cmp(gconstpointer a, gconstpointer b) { const struct gatt_primary *prim = a; const char *uuid = b; return g_strcmp0(prim->uuid, uuid); } static int attio_device_probe(struct btd_device *device, GSList *uuids) { struct gatt_primary *linkloss, *txpower, *immediate; GSList *l, *primaries; primaries = btd_device_get_primaries(device); l = g_slist_find_custom(primaries, IMMEDIATE_ALERT_UUID, primary_uuid_cmp); immediate = (l ? l->data : NULL); l = g_slist_find_custom(primaries, TX_POWER_UUID, primary_uuid_cmp); txpower = (l ? l->data : NULL); l = g_slist_find_custom(primaries, LINK_LOSS_UUID, primary_uuid_cmp); linkloss = (l ? l->data : NULL); return monitor_register(connection, device, linkloss, txpower, immediate, &enabled); } static void attio_device_remove(struct btd_device *device) { monitor_unregister(connection, device); } static struct btd_device_driver monitor_driver = { .name = "Proximity GATT Monitor Driver", .uuids = BTD_UUIDS(IMMEDIATE_ALERT_UUID, LINK_LOSS_UUID, TX_POWER_UUID), .probe = attio_device_probe, .remove = attio_device_remove, }; static struct btd_adapter_driver reporter_server_driver = { .name = "Proximity GATT Reporter Driver", .probe = reporter_init, .remove = reporter_exit, }; static void load_config_file(GKeyFile *config) { char **list; int i; if (config == NULL) return; list = g_key_file_get_string_list(config, "General", "Disable", NULL, NULL); for (i = 0; list && list[i] != NULL; i++) { if (g_str_equal(list[i], "FindMe")) enabled.findme = FALSE; else if (g_str_equal(list[i], "LinkLoss")) enabled.linkloss = FALSE; else if (g_str_equal(list[i], "PathLoss")) enabled.pathloss = FALSE; } g_strfreev(list); } int proximity_manager_init(DBusConnection *conn, GKeyFile *config) { int ret; load_config_file(config); connection = dbus_connection_ref(conn); ret = btd_register_device_driver(&monitor_driver); if (ret < 0) goto fail_monitor; ret = btd_register_adapter_driver(&reporter_server_driver); if (ret < 0) goto fail_reporter; return 0; fail_reporter: btd_unregister_device_driver(&monitor_driver); fail_monitor: dbus_connection_unref(connection); return ret; } void proximity_manager_exit(void) { btd_unregister_device_driver(&monitor_driver); btd_unregister_adapter_driver(&reporter_server_driver); dbus_connection_unref(connection); } bluez-4.101/proximity/monitor.h0000644000000000000000000000233511766125764013455 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ struct enabled { gboolean linkloss; gboolean pathloss; gboolean findme; }; int monitor_register(DBusConnection *conn, struct btd_device *device, struct gatt_primary *linkloss, struct gatt_primary *txpower, struct gatt_primary *immediate, struct enabled *enabled); void monitor_unregister(DBusConnection *conn, struct btd_device *device); bluez-4.101/proximity/immalert.c0000644000000000000000000001560711766125764013601 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "log.h" #include "gattrib.h" #include "att.h" #include "gatt.h" #include "att-database.h" #include "gatt-service.h" #include "attrib-server.h" #include "device.h" #include "attio.h" #include "dbus-common.h" #include "reporter.h" #include "immalert.h" struct imm_alert_adapter { struct btd_adapter *adapter; DBusConnection *conn; GSList *connected_devices; }; struct connected_device { struct btd_device *device; struct imm_alert_adapter *adapter; uint8_t alert_level; guint callback_id; }; static GSList *imm_alert_adapters; static int imdevice_cmp(gconstpointer a, gconstpointer b) { const struct connected_device *condev = a; const struct btd_device *device = b; if (condev->device == device) return 0; return -1; } static struct connected_device * find_connected_device(struct imm_alert_adapter *ia, struct btd_device *device) { GSList *l = g_slist_find_custom(ia->connected_devices, device, imdevice_cmp); if (!l) return NULL; return l->data; } static int imadapter_cmp(gconstpointer a, gconstpointer b) { const struct imm_alert_adapter *imadapter = a; const struct btd_adapter *adapter = b; if (imadapter->adapter == adapter) return 0; return -1; } static struct imm_alert_adapter * find_imm_alert_adapter(struct btd_adapter *adapter) { GSList *l = g_slist_find_custom(imm_alert_adapters, adapter, imadapter_cmp); if (!l) return NULL; return l->data; } const char *imm_alert_get_level(struct btd_device *device) { struct imm_alert_adapter *imadapter; struct connected_device *condev; if (!device) return get_alert_level_string(NO_ALERT); imadapter = find_imm_alert_adapter(device_get_adapter(device)); if (!imadapter) return get_alert_level_string(NO_ALERT); condev = find_connected_device(imadapter, device); if (!condev) return get_alert_level_string(NO_ALERT); return get_alert_level_string(condev->alert_level); } static void imm_alert_emit_alert_signal(struct connected_device *condev, uint8_t alert_level) { struct imm_alert_adapter *adapter; const char *path, *alert_level_str; if (!condev) return; adapter = condev->adapter; path = device_get_path(condev->device); alert_level_str = get_alert_level_string(alert_level); DBG("alert %s remote %s", alert_level_str, path); emit_property_changed(adapter->conn, path, PROXIMITY_REPORTER_INTERFACE, "ImmediateAlertLevel", DBUS_TYPE_STRING, &alert_level_str); } static void imm_alert_remove_condev(struct connected_device *condev) { struct imm_alert_adapter *ia; if (!condev) return; ia = condev->adapter; if (condev->callback_id && condev->device) btd_device_remove_attio_callback(condev->device, condev->callback_id); if (condev->device) btd_device_unref(condev->device); ia->connected_devices = g_slist_remove(ia->connected_devices, condev); g_free(condev); } /* condev can be NULL */ static void imm_alert_disc_cb(gpointer user_data) { struct connected_device *condev = user_data; if (!condev) return; DBG("immediate alert remove device %p", condev->device); imm_alert_emit_alert_signal(condev, NO_ALERT); imm_alert_remove_condev(condev); } static uint8_t imm_alert_alert_lvl_write(struct attribute *a, struct btd_device *device, gpointer user_data) { uint8_t value; struct imm_alert_adapter *ia = user_data; struct connected_device *condev = NULL; if (!device) goto set_error; condev = find_connected_device(ia, device); if (a->len == 0) { DBG("Illegal alert level length"); goto set_error; } value = a->data[0]; if (value != NO_ALERT && value != MILD_ALERT && value != HIGH_ALERT) { DBG("Illegal alert value"); goto set_error; } /* Register a disconnect cb if the alert level is non-zero */ if (value != NO_ALERT && !condev) { condev = g_new0(struct connected_device, 1); condev->device = btd_device_ref(device); condev->adapter = ia; condev->callback_id = btd_device_add_attio_callback(device, NULL, imm_alert_disc_cb, condev); ia->connected_devices = g_slist_append(ia->connected_devices, condev); DBG("added connected dev %p", device); } if (value != NO_ALERT) { condev->alert_level = value; imm_alert_emit_alert_signal(condev, value); } /* * Emit NO_ALERT if the alert level was non-zero before. This is * guaranteed when there's a condev. */ if (value == NO_ALERT && condev) imm_alert_disc_cb(condev); DBG("alert level set to %d by device %p", value, device); return 0; set_error: error("Set immediate alert level for dev %p", device); /* remove alerts by erroneous devices */ imm_alert_disc_cb(condev); return ATT_ECODE_IO; } void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn) { gboolean svc_added; bt_uuid_t uuid; struct imm_alert_adapter *imadapter; bt_uuid16_create(&uuid, IMMEDIATE_ALERT_SVC_UUID); imadapter = g_new0(struct imm_alert_adapter, 1); imadapter->adapter = adapter; imadapter->conn = dbus_connection_ref(conn); imm_alert_adapters = g_slist_append(imm_alert_adapters, imadapter); /* Immediate Alert Service */ svc_added = gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid, /* Alert level characteristic */ GATT_OPT_CHR_UUID, ALERT_LEVEL_CHR_UUID, GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE_WITHOUT_RESP, GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE, imm_alert_alert_lvl_write, imadapter, GATT_OPT_INVALID); if (!svc_added) { imm_alert_unregister(adapter); return; } DBG("Immediate Alert service added"); } static void remove_condev_list_item(gpointer data, gpointer user_data) { struct connected_device *condev = data; imm_alert_remove_condev(condev); } void imm_alert_unregister(struct btd_adapter *adapter) { struct imm_alert_adapter *imadapter; imadapter = find_imm_alert_adapter(adapter); if (!imadapter) return; g_slist_foreach(imadapter->connected_devices, remove_condev_list_item, NULL); dbus_connection_unref(imadapter->conn); imm_alert_adapters = g_slist_remove(imm_alert_adapters, imadapter); g_free(imadapter); } bluez-4.101/emulator/0000755000000000000000000000000011771120004011430 500000000000000bluez-4.101/emulator/server.c0000644000000000000000000001326111766125764013053 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "mainloop.h" #include "btdev.h" #include "server.h" struct server { uint16_t id; int fd; }; struct client { int fd; struct btdev *btdev; uint8_t *pkt_data; uint8_t pkt_type; uint16_t pkt_expect; uint16_t pkt_len; uint16_t pkt_offset; }; static void server_destroy(void *user_data) { struct server *server = user_data; close(server->fd); free(server); } static void client_destroy(void *user_data) { struct client *client = user_data; btdev_destroy(client->btdev); close(client->fd); free(client); } static void client_write_callback(const void *data, uint16_t len, void *user_data) { struct client *client = user_data; ssize_t written; written = send(client->fd, data, len, MSG_DONTWAIT); if (written < 0) return; } static void client_read_callback(int fd, uint32_t events, void *user_data) { struct client *client = user_data; static uint8_t buf[4096]; uint8_t *ptr = buf; ssize_t len; uint16_t count; if (events & (EPOLLERR | EPOLLHUP)) return; again: len = recv(fd, buf + client->pkt_offset, sizeof(buf) - client->pkt_offset, MSG_DONTWAIT); if (len < 0) { if (errno == EAGAIN) goto again; return; } count = client->pkt_offset + len; while (count > 0) { hci_command_hdr *cmd_hdr; if (!client->pkt_data) { client->pkt_type = ptr[0]; switch (client->pkt_type) { case HCI_COMMAND_PKT: if (count < HCI_COMMAND_HDR_SIZE + 1) { client->pkt_offset += len; return; } cmd_hdr = (hci_command_hdr *) (ptr + 1); client->pkt_expect = HCI_COMMAND_HDR_SIZE + cmd_hdr->plen + 1; client->pkt_data = malloc(client->pkt_expect); client->pkt_len = 0; break; default: printf("packet error\n"); return; } client->pkt_offset = 0; } if (count >= client->pkt_expect) { memcpy(client->pkt_data + client->pkt_len, ptr, client->pkt_expect); ptr += client->pkt_expect; count -= client->pkt_expect; btdev_receive_h4(client->btdev, client->pkt_data, client->pkt_len + client->pkt_expect); free(client->pkt_data); client->pkt_data = NULL; } else { memcpy(client->pkt_data + client->pkt_len, ptr, count); client->pkt_len += count; client->pkt_expect -= count; count = 0; } } } static int accept_client(int fd) { struct sockaddr_un addr; socklen_t len; int nfd; memset(&addr, 0, sizeof(addr)); len = sizeof(addr); if (getsockname(fd, (struct sockaddr *) &addr, &len) < 0) { perror("Failed to get socket name"); return -1; } printf("Request for %s\n", addr.sun_path); nfd = accept(fd, (struct sockaddr *) &addr, &len); if (nfd < 0) { perror("Failed to accept client socket"); return -1; } return nfd; } static void server_accept_callback(int fd, uint32_t events, void *user_data) { struct server *server = user_data; struct client *client; if (events & (EPOLLERR | EPOLLHUP)) return; client = malloc(sizeof(*client)); if (!client) return; memset(client, 0, sizeof(*client)); client->fd = accept_client(server->fd); if (client->fd < 0) { free(client); return; } client->btdev = btdev_create(server->id); if (!client->btdev) { close(client->fd); free(client); return; } btdev_set_send_handler(client->btdev, client_write_callback, client); if (mainloop_add_fd(client->fd, EPOLLIN, client_read_callback, client, client_destroy) < 0) { btdev_destroy(client->btdev); close(client->fd); free(client); } } static int open_server(const char *path) { struct sockaddr_un addr; int fd; unlink(path); fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { perror("Failed to open server socket"); return -1; } memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; strcpy(addr.sun_path, path); if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) { perror("Failed to bind server socket"); close(fd); return -1; } if (listen(fd, 5) < 0) { perror("Failed to listen server socket"); close(fd); return -1; } return fd; } struct server *server_open_unix(const char *path, uint16_t id) { struct server *server; server = malloc(sizeof(*server)); if (!server) return NULL; memset(server, 0, sizeof(*server)); server->id = id; server->fd = open_server(path); if (server->fd < 0) { free(server); return NULL; } if (mainloop_add_fd(server->fd, EPOLLIN, server_accept_callback, server, server_destroy) < 0) { close(server->fd); free(server); return NULL; } return server; } void server_close(struct server *server) { if (!server) return; mainloop_remove_fd(server->fd); } bluez-4.101/emulator/vhci.h0000644000000000000000000000211511766125764012477 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include enum vhci_type { VHCI_TYPE_BREDR = 0, VHCI_TYPE_AMP = 1, }; struct vhci; struct vhci *vhci_open(enum vhci_type type, uint16_t id); void vhci_close(struct vhci *vhci); bluez-4.101/emulator/btdev.c0000644000000000000000000007034511766125764012657 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "bt.h" #include "btdev.h" #define le16_to_cpu(val) (val) #define cpu_to_le16(val) (val) struct btdev { struct btdev *conn; btdev_send_func send_handler; void *send_data; uint16_t manufacturer; uint8_t version; uint16_t revision; uint8_t commands[64]; uint8_t features[8]; uint16_t acl_mtu; uint16_t acl_max_pkt; uint8_t country_code; uint8_t bdaddr[6]; uint8_t le_features[8]; uint8_t le_states[8]; uint16_t default_link_policy; uint8_t event_mask[8]; uint8_t event_filter; uint8_t name[248]; uint8_t dev_class[3]; uint16_t voice_setting; uint16_t conn_accept_timeout; uint16_t page_timeout; uint8_t scan_enable; uint8_t auth_enable; uint8_t inquiry_mode; uint8_t afh_assess_mode; uint8_t ext_inquiry_fec; uint8_t ext_inquiry_rsp[240]; uint8_t simple_pairing_mode; uint8_t le_supported; uint8_t le_simultaneous; uint8_t le_event_mask[8]; }; #define MAX_BTDEV_ENTRIES 16 static struct btdev *btdev_list[MAX_BTDEV_ENTRIES] = { }; static inline int add_btdev(struct btdev *btdev) { int i, index = -1; for (i = 0; i < MAX_BTDEV_ENTRIES; i++) { if (btdev_list[i] == NULL) { index = i; btdev_list[index] = btdev; break; } } return index; } static inline int del_btdev(struct btdev *btdev) { int i, index = -1; for (i = 0; i < MAX_BTDEV_ENTRIES; i++) { if (btdev_list[i] == btdev) { index = i; btdev_list[index] = NULL; break; } } return index; } static inline struct btdev *find_btdev_by_bdaddr(const uint8_t *bdaddr) { int i; for (i = 0; i < MAX_BTDEV_ENTRIES; i++) { if (btdev_list[i] && !memcmp(btdev_list[i]->bdaddr, bdaddr, 6)) return btdev_list[i]; } return NULL; } static void hexdump(const unsigned char *buf, uint16_t len) { static const char hexdigits[] = "0123456789abcdef"; char str[68]; uint16_t i; if (!len) return; for (i = 0; i < len; i++) { str[((i % 16) * 3) + 0] = hexdigits[buf[i] >> 4]; str[((i % 16) * 3) + 1] = hexdigits[buf[i] & 0xf]; str[((i % 16) * 3) + 2] = ' '; str[(i % 16) + 49] = isprint(buf[i]) ? buf[i] : '.'; if ((i + 1) % 16 == 0) { str[47] = ' '; str[48] = ' '; str[65] = '\0'; printf("%-12c%s\n", ' ', str); str[0] = ' '; } } if (i % 16 > 0) { uint16_t j; for (j = (i % 16); j < 16; j++) { str[(j * 3) + 0] = ' '; str[(j * 3) + 1] = ' '; str[(j * 3) + 2] = ' '; str[j + 49] = ' '; } str[47] = ' '; str[48] = ' '; str[65] = '\0'; printf("%-12c%s\n", ' ', str); } } static void get_bdaddr(uint16_t id, uint8_t *bdaddr) { bdaddr[0] = id & 0xff; bdaddr[1] = id >> 8; bdaddr[2] = 0x00; bdaddr[3] = 0x01; bdaddr[4] = 0xaa; bdaddr[5] = 0x00; } struct btdev *btdev_create(uint16_t id) { struct btdev *btdev; btdev = malloc(sizeof(*btdev)); if (!btdev) return NULL; memset(btdev, 0, sizeof(*btdev)); btdev->manufacturer = 63; btdev->version = 0x06; btdev->revision = 0x0000; btdev->features[0] |= 0x04; /* Encryption */ btdev->features[0] |= 0x20; /* Role switch */ btdev->features[0] |= 0x80; /* Sniff mode */ btdev->features[1] |= 0x08; /* SCO link */ btdev->features[3] |= 0x40; /* RSSI with inquiry results */ btdev->features[3] |= 0x80; /* Extended SCO link */ btdev->features[4] |= 0x08; /* AFH capable slave */ btdev->features[4] |= 0x10; /* AFH classification slave */ btdev->features[4] |= 0x40; /* LE Supported */ btdev->features[5] |= 0x02; /* Sniff subrating */ btdev->features[5] |= 0x04; /* Pause encryption */ btdev->features[5] |= 0x08; /* AFH capable master */ btdev->features[5] |= 0x10; /* AFH classification master */ btdev->features[6] |= 0x01; /* Extended Inquiry Response */ btdev->features[6] |= 0x02; /* Simultaneous LE and BR/EDR */ btdev->features[6] |= 0x08; /* Secure Simple Pairing */ btdev->features[6] |= 0x10; /* Encapsulated PDU */ btdev->features[6] |= 0x20; /* Erroneous Data Reporting */ btdev->features[6] |= 0x40; /* Non-flushable Packet Boundary Flag */ btdev->features[7] |= 0x01; /* Link Supervision Timeout Event */ btdev->features[7] |= 0x02; /* Inquiry TX Power Level */ btdev->features[7] |= 0x80; /* Extended features */ btdev->acl_mtu = 192; btdev->acl_max_pkt = 1; btdev->country_code = 0x00; get_bdaddr(id, btdev->bdaddr); add_btdev(btdev); return btdev; } void btdev_destroy(struct btdev *btdev) { if (!btdev) return; del_btdev(btdev); free(btdev); } void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler, void *user_data) { if (!btdev) return; btdev->send_handler = handler; btdev->send_data = user_data; } static void send_packet(struct btdev *btdev, const void *data, uint16_t len) { if (!btdev->send_handler) return; btdev->send_handler(data, len, btdev->send_data); } static void send_event(struct btdev *btdev, uint8_t event, const void *data, uint8_t len) { struct bt_hci_evt_hdr *hdr; uint16_t pkt_len; void *pkt_data; pkt_len = 1 + sizeof(*hdr) + len; pkt_data = malloc(pkt_len); if (!pkt_data) return; ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT; hdr = pkt_data + 1; hdr->evt = event; hdr->plen = len; if (len > 0) memcpy(pkt_data + 1 + sizeof(*hdr), data, len); send_packet(btdev, pkt_data, pkt_len); free(pkt_data); } static void cmd_complete(struct btdev *btdev, uint16_t opcode, const void *data, uint8_t len) { struct bt_hci_evt_hdr *hdr; struct bt_hci_evt_cmd_complete *cc; uint16_t pkt_len; void *pkt_data; pkt_len = 1 + sizeof(*hdr) + sizeof(*cc) + len; pkt_data = malloc(pkt_len); if (!pkt_data) return; ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT; hdr = pkt_data + 1; hdr->evt = BT_HCI_EVT_CMD_COMPLETE; hdr->plen = sizeof(*cc) + len; cc = pkt_data + 1 + sizeof(*hdr); cc->ncmd = 0x01; cc->opcode = cpu_to_le16(opcode); if (len > 0) memcpy(pkt_data + 1 + sizeof(*hdr) + sizeof(*cc), data, len); send_packet(btdev, pkt_data, pkt_len); free(pkt_data); } static void cmd_status(struct btdev *btdev, uint8_t status, uint16_t opcode) { struct bt_hci_evt_cmd_status cs; cs.status = status; cs.ncmd = 0x01; cs.opcode = cpu_to_le16(opcode); send_event(btdev, BT_HCI_EVT_CMD_STATUS, &cs, sizeof(cs)); } static void num_completed_packets(struct btdev *btdev) { if (btdev->conn) { struct bt_hci_evt_num_completed_packets ncp; ncp.num_handles = 1; ncp.handle = cpu_to_le16(42); ncp.count = cpu_to_le16(1); send_event(btdev, BT_HCI_EVT_NUM_COMPLETED_PACKETS, &ncp, sizeof(ncp)); } } static void inquiry_complete(struct btdev *btdev, uint8_t status) { struct bt_hci_evt_inquiry_complete ic; int i; for (i = 0; i < MAX_BTDEV_ENTRIES; i++) { if (!btdev_list[i] || btdev_list[i] == btdev) continue; if (!(btdev_list[i]->scan_enable & 0x02)) continue; if (btdev->inquiry_mode == 0x02 && btdev_list[i]->ext_inquiry_rsp[0]) { struct bt_hci_evt_ext_inquiry_result ir; ir.num_resp = 0x01; memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6); memcpy(ir.dev_class, btdev_list[i]->dev_class, 3); ir.rssi = -60; memcpy(ir.data, btdev_list[i]->ext_inquiry_rsp, 240); send_event(btdev, BT_HCI_EVT_EXT_INQUIRY_RESULT, &ir, sizeof(ir)); continue; } if (btdev->inquiry_mode > 0x00) { struct bt_hci_evt_inquiry_result_with_rssi ir; ir.num_resp = 0x01; memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6); memcpy(ir.dev_class, btdev_list[i]->dev_class, 3); ir.rssi = -60; send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI, &ir, sizeof(ir)); } else { struct bt_hci_evt_inquiry_result ir; ir.num_resp = 0x01; memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6); memcpy(ir.dev_class, btdev_list[i]->dev_class, 3); send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT, &ir, sizeof(ir)); } } ic.status = status; send_event(btdev, BT_HCI_EVT_INQUIRY_COMPLETE, &ic, sizeof(ic)); } static void conn_complete(struct btdev *btdev, const uint8_t *bdaddr, uint8_t status) { struct bt_hci_evt_conn_complete cc; if (!status) { struct btdev *remote = find_btdev_by_bdaddr(bdaddr); btdev->conn = remote; remote->conn = btdev; cc.status = status; memcpy(cc.bdaddr, btdev->bdaddr, 6); cc.encr_mode = 0x00; cc.handle = cpu_to_le16(42); cc.link_type = 0x01; send_event(remote, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc)); cc.handle = cpu_to_le16(42); cc.link_type = 0x01; } else { cc.handle = cpu_to_le16(0x0000); cc.link_type = 0x01; } cc.status = status; memcpy(cc.bdaddr, bdaddr, 6); cc.encr_mode = 0x00; send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc)); } static void conn_request(struct btdev *btdev, const uint8_t *bdaddr) { struct btdev *remote = find_btdev_by_bdaddr(bdaddr); if (remote) { if (remote->scan_enable & 0x01) { struct bt_hci_evt_conn_request cr; memcpy(cr.bdaddr, btdev->bdaddr, 6); memcpy(cr.dev_class, btdev->dev_class, 3); cr.link_type = 0x01; send_event(remote, BT_HCI_EVT_CONN_REQUEST, &cr, sizeof(cr)); } else conn_complete(btdev, bdaddr, BT_HCI_ERR_PAGE_TIMEOUT); } else conn_complete(btdev, bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID); } static void disconnect_complete(struct btdev *btdev, uint16_t handle, uint8_t reason) { struct bt_hci_evt_disconnect_complete dc; struct btdev *remote; if (!btdev) { dc.status = BT_HCI_ERR_UNKNOWN_CONN_ID; dc.handle = cpu_to_le16(handle); dc.reason = 0x00; send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc)); return; } dc.status = BT_HCI_ERR_SUCCESS; dc.handle = cpu_to_le16(handle); dc.reason = reason; remote = btdev->conn; btdev->conn = NULL; remote->conn = NULL; send_event(btdev, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc)); send_event(remote, BT_HCI_EVT_DISCONNECT_COMPLETE, &dc, sizeof(dc)); } static void name_request_complete(struct btdev *btdev, const uint8_t *bdaddr, uint8_t status) { struct bt_hci_evt_remote_name_req_complete nc; nc.status = status; memcpy(nc.bdaddr, bdaddr, 6); memset(nc.name, 0, 248); if (!status) { struct btdev *remote = find_btdev_by_bdaddr(bdaddr); if (remote) memcpy(nc.name, remote->name, 248); else nc.status = BT_HCI_ERR_UNKNOWN_CONN_ID; } send_event(btdev, BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE, &nc, sizeof(nc)); } static void remote_features_complete(struct btdev *btdev, uint16_t handle) { struct bt_hci_evt_remote_features_complete rfc; if (btdev->conn) { rfc.status = BT_HCI_ERR_SUCCESS; rfc.handle = cpu_to_le16(handle); memcpy(rfc.features, btdev->conn->features, 8); } else { rfc.status = BT_HCI_ERR_UNKNOWN_CONN_ID; rfc.handle = cpu_to_le16(handle); memset(rfc.features, 0, 8); } send_event(btdev, BT_HCI_EVT_REMOTE_FEATURES_COMPLETE, &rfc, sizeof(rfc)); } static void remote_ext_features_complete(struct btdev *btdev, uint16_t handle, uint8_t page) { struct bt_hci_evt_remote_ext_features_complete refc; if (btdev->conn && page < 0x02) { refc.handle = cpu_to_le16(handle); refc.page = page; refc.max_page = 0x01; switch (page) { case 0x00: refc.status = BT_HCI_ERR_SUCCESS; memcpy(refc.features, btdev->conn->features, 8); break; case 0x01: refc.status = BT_HCI_ERR_SUCCESS; memset(refc.features, 0, 8); break; default: refc.status = BT_HCI_ERR_INVALID_PARAMETERS; memset(refc.features, 0, 8); break; } } else { refc.status = BT_HCI_ERR_UNKNOWN_CONN_ID; refc.handle = cpu_to_le16(handle); refc.page = page; refc.max_page = 0x01; memset(refc.features, 0, 8); } send_event(btdev, BT_HCI_EVT_REMOTE_EXT_FEATURES_COMPLETE, &refc, sizeof(refc)); } static void remote_version_complete(struct btdev *btdev, uint16_t handle) { struct bt_hci_evt_remote_version_complete rvc; if (btdev->conn) { rvc.status = BT_HCI_ERR_SUCCESS; rvc.handle = cpu_to_le16(handle); rvc.lmp_ver = btdev->conn->version; rvc.manufacturer = cpu_to_le16(btdev->conn->manufacturer); rvc.lmp_subver = cpu_to_le16(btdev->conn->revision); } else { rvc.status = BT_HCI_ERR_UNKNOWN_CONN_ID; rvc.handle = cpu_to_le16(handle); rvc.lmp_ver = 0x00; rvc.manufacturer = cpu_to_le16(0); rvc.lmp_subver = cpu_to_le16(0); } send_event(btdev, BT_HCI_EVT_REMOTE_VERSION_COMPLETE, &rvc, sizeof(rvc)); } static void process_cmd(struct btdev *btdev, const void *data, uint16_t len) { const struct bt_hci_cmd_hdr *hdr = data; const struct bt_hci_cmd_create_conn *cc; const struct bt_hci_cmd_disconnect *dc; const struct bt_hci_cmd_create_conn_cancel *ccc; const struct bt_hci_cmd_accept_conn_request *acr; const struct bt_hci_cmd_reject_conn_request *rcr; const struct bt_hci_cmd_remote_name_request *rnr; const struct bt_hci_cmd_remote_name_request_cancel *rnrc; const struct bt_hci_cmd_read_remote_features *rrf; const struct bt_hci_cmd_read_remote_ext_features *rref; const struct bt_hci_cmd_read_remote_version *rrv; const struct bt_hci_cmd_write_default_link_policy *wdlp; const struct bt_hci_cmd_set_event_mask *sem; const struct bt_hci_cmd_set_event_filter *sef; const struct bt_hci_cmd_write_local_name *wln; const struct bt_hci_cmd_write_conn_accept_timeout *wcat; const struct bt_hci_cmd_write_page_timeout *wpt; const struct bt_hci_cmd_write_scan_enable *wse; const struct bt_hci_cmd_write_auth_enable *wae; const struct bt_hci_cmd_write_class_of_dev *wcod; const struct bt_hci_cmd_write_voice_setting *wvs; const struct bt_hci_cmd_write_inquiry_mode *wim; const struct bt_hci_cmd_write_afh_assess_mode *waam; const struct bt_hci_cmd_write_ext_inquiry_rsp *weir; const struct bt_hci_cmd_write_simple_pairing_mode *wspm; const struct bt_hci_cmd_write_le_host_supported *wlhs; const struct bt_hci_cmd_le_set_event_mask *lsem; struct bt_hci_rsp_read_default_link_policy rdlp; struct bt_hci_rsp_read_stored_link_key rslk; struct bt_hci_rsp_write_stored_link_key wslk; struct bt_hci_rsp_delete_stored_link_key dslk; struct bt_hci_rsp_read_local_name rln; struct bt_hci_rsp_read_conn_accept_timeout rcat; struct bt_hci_rsp_read_page_timeout rpt; struct bt_hci_rsp_read_scan_enable rse; struct bt_hci_rsp_read_auth_enable rae; struct bt_hci_rsp_read_class_of_dev rcod; struct bt_hci_rsp_read_voice_setting rvs; struct bt_hci_rsp_read_inquiry_mode rim; struct bt_hci_rsp_read_afh_assess_mode raam; struct bt_hci_rsp_read_ext_inquiry_rsp reir; struct bt_hci_rsp_read_simple_pairing_mode rspm; struct bt_hci_rsp_read_inquiry_rsp_tx_power rirtp; struct bt_hci_rsp_read_le_host_supported rlhs; struct bt_hci_rsp_read_local_version rlv; struct bt_hci_rsp_read_local_commands rlc; struct bt_hci_rsp_read_local_features rlf; struct bt_hci_rsp_read_local_ext_features rlef; struct bt_hci_rsp_read_buffer_size rbs; struct bt_hci_rsp_read_country_code rcc; struct bt_hci_rsp_read_bd_addr rba; struct bt_hci_rsp_read_data_block_size rdbs; struct bt_hci_rsp_le_read_buffer_size lrbs; struct bt_hci_rsp_le_read_local_features lrlf; struct bt_hci_rsp_le_read_supported_states lrss; uint16_t opcode; uint8_t status, page; if (len < sizeof(*hdr)) return; opcode = le16_to_cpu(hdr->opcode); switch (opcode) { case BT_HCI_CMD_INQUIRY: cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); inquiry_complete(btdev, BT_HCI_ERR_SUCCESS); break; case BT_HCI_CMD_INQUIRY_CANCEL: status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_CREATE_CONN: cc = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); conn_request(btdev, cc->bdaddr); break; case BT_HCI_CMD_DISCONNECT: dc = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason); break; case BT_HCI_CMD_CREATE_CONN_CANCEL: ccc = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID); break; case BT_HCI_CMD_ACCEPT_CONN_REQUEST: acr = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS); break; case BT_HCI_CMD_REJECT_CONN_REQUEST: rcr = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID); break; case BT_HCI_CMD_REMOTE_NAME_REQUEST: rnr = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS); break; case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL: rnrc = data + sizeof(*hdr); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); name_request_complete(btdev, rnrc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID); break; case BT_HCI_CMD_READ_REMOTE_FEATURES: rrf = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); remote_features_complete(btdev, le16_to_cpu(rrf->handle)); break; case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES: rref = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); remote_ext_features_complete(btdev, le16_to_cpu(rref->handle), rref->page); break; case BT_HCI_CMD_READ_REMOTE_VERSION: rrv = data + sizeof(*hdr); cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode); remote_version_complete(btdev, le16_to_cpu(rrv->handle)); break; case BT_HCI_CMD_READ_DEFAULT_LINK_POLICY: rdlp.status = BT_HCI_ERR_SUCCESS; rdlp.policy = cpu_to_le16(btdev->default_link_policy); cmd_complete(btdev, opcode, &rdlp, sizeof(rdlp)); break; case BT_HCI_CMD_WRITE_DEFAULT_LINK_POLICY: wdlp = data + sizeof(*hdr); btdev->default_link_policy = le16_to_cpu(wdlp->policy); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_SET_EVENT_MASK: sem = data + sizeof(*hdr); memcpy(btdev->event_mask, sem->mask, 8); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_RESET: status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_SET_EVENT_FILTER: sef = data + sizeof(*hdr); btdev->event_filter = sef->type; status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_STORED_LINK_KEY: rslk.status = BT_HCI_ERR_SUCCESS; rslk.max_num_keys = cpu_to_le16(0); rslk.num_keys = cpu_to_le16(0); cmd_complete(btdev, opcode, &rslk, sizeof(rslk)); break; case BT_HCI_CMD_WRITE_STORED_LINK_KEY: wslk.status = BT_HCI_ERR_SUCCESS; wslk.num_keys = 0; cmd_complete(btdev, opcode, &wslk, sizeof(wslk)); break; case BT_HCI_CMD_DELETE_STORED_LINK_KEY: dslk.status = BT_HCI_ERR_SUCCESS; dslk.num_keys = cpu_to_le16(0); cmd_complete(btdev, opcode, &dslk, sizeof(dslk)); break; case BT_HCI_CMD_WRITE_LOCAL_NAME: wln = data + sizeof(*hdr); memcpy(btdev->name, wln->name, 248); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_LOCAL_NAME: rln.status = BT_HCI_ERR_SUCCESS; memcpy(rln.name, btdev->name, 248); cmd_complete(btdev, opcode, &rln, sizeof(rln)); break; case BT_HCI_CMD_READ_CONN_ACCEPT_TIMEOUT: rcat.status = BT_HCI_ERR_SUCCESS; rcat.timeout = cpu_to_le16(btdev->conn_accept_timeout); cmd_complete(btdev, opcode, &rcat, sizeof(rcat)); break; case BT_HCI_CMD_WRITE_CONN_ACCEPT_TIMEOUT: wcat = data + sizeof(*hdr); btdev->conn_accept_timeout = le16_to_cpu(wcat->timeout); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_PAGE_TIMEOUT: rpt.status = BT_HCI_ERR_SUCCESS; rpt.timeout = cpu_to_le16(btdev->page_timeout); cmd_complete(btdev, opcode, &rpt, sizeof(rpt)); break; case BT_HCI_CMD_WRITE_PAGE_TIMEOUT: wpt = data + sizeof(*hdr); btdev->page_timeout = le16_to_cpu(wpt->timeout); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_SCAN_ENABLE: rse.status = BT_HCI_ERR_SUCCESS; rse.enable = btdev->scan_enable; cmd_complete(btdev, opcode, &rse, sizeof(rse)); break; case BT_HCI_CMD_WRITE_SCAN_ENABLE: wse = data + sizeof(*hdr); btdev->scan_enable = wse->enable; status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_AUTH_ENABLE: rae.status = BT_HCI_ERR_SUCCESS; rae.enable = btdev->auth_enable; cmd_complete(btdev, opcode, &rae, sizeof(rae)); break; case BT_HCI_CMD_WRITE_AUTH_ENABLE: wae = data + sizeof(*hdr); btdev->auth_enable = wae->enable; status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_CLASS_OF_DEV: rcod.status = BT_HCI_ERR_SUCCESS; memcpy(rcod.dev_class, btdev->dev_class, 3); cmd_complete(btdev, opcode, &rcod, sizeof(rcod)); break; case BT_HCI_CMD_WRITE_CLASS_OF_DEV: wcod = data + sizeof(*hdr); memcpy(btdev->dev_class, wcod->dev_class, 3); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_VOICE_SETTING: rvs.status = BT_HCI_ERR_SUCCESS; rvs.setting = cpu_to_le16(btdev->voice_setting); cmd_complete(btdev, opcode, &rvs, sizeof(rvs)); break; case BT_HCI_CMD_WRITE_VOICE_SETTING: wvs = data + sizeof(*hdr); btdev->voice_setting = le16_to_cpu(wvs->setting); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_INQUIRY_MODE: rim.status = BT_HCI_ERR_SUCCESS; rim.mode = btdev->inquiry_mode; cmd_complete(btdev, opcode, &rim, sizeof(rim)); break; case BT_HCI_CMD_WRITE_INQUIRY_MODE: wim = data + sizeof(*hdr); btdev->inquiry_mode = wim->mode; status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_AFH_ASSESS_MODE: raam.status = BT_HCI_ERR_SUCCESS; raam.mode = btdev->afh_assess_mode; cmd_complete(btdev, opcode, &raam, sizeof(raam)); break; case BT_HCI_CMD_WRITE_AFH_ASSESS_MODE: waam = data + sizeof(*hdr); btdev->afh_assess_mode = waam->mode; status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_EXT_INQUIRY_RSP: reir.status = BT_HCI_ERR_SUCCESS; reir.fec = btdev->ext_inquiry_fec; memcpy(reir.data, btdev->ext_inquiry_rsp, 240); cmd_complete(btdev, opcode, &reir, sizeof(reir)); break; case BT_HCI_CMD_WRITE_EXT_INQUIRY_RSP: weir = data + sizeof(*hdr); btdev->ext_inquiry_fec = weir->fec; memcpy(btdev->ext_inquiry_rsp, weir->data, 240); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE: rspm.status = BT_HCI_ERR_SUCCESS; rspm.mode = btdev->simple_pairing_mode; cmd_complete(btdev, opcode, &rspm, sizeof(rspm)); break; case BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE: wspm = data + sizeof(*hdr); btdev->simple_pairing_mode = wspm->mode; status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_INQUIRY_RSP_TX_POWER: rirtp.status = BT_HCI_ERR_SUCCESS; rirtp.level = 0; cmd_complete(btdev, opcode, &rirtp, sizeof(rirtp)); break; case BT_HCI_CMD_READ_LE_HOST_SUPPORTED: rlhs.status = BT_HCI_ERR_SUCCESS; rlhs.supported = btdev->le_supported; rlhs.simultaneous = btdev->le_simultaneous; cmd_complete(btdev, opcode, &rlhs, sizeof(rlhs)); break; case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED: wlhs = data + sizeof(*hdr); btdev->le_supported = wlhs->supported; btdev->le_simultaneous = wlhs->simultaneous; status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_READ_LOCAL_VERSION: rlv.status = BT_HCI_ERR_SUCCESS; rlv.hci_ver = btdev->version; rlv.hci_rev = cpu_to_le16(btdev->revision); rlv.lmp_ver = btdev->version; rlv.manufacturer = cpu_to_le16(btdev->manufacturer); rlv.lmp_subver = cpu_to_le16(btdev->revision); cmd_complete(btdev, opcode, &rlv, sizeof(rlv)); break; case BT_HCI_CMD_READ_LOCAL_COMMANDS: rlc.status = BT_HCI_ERR_SUCCESS; memcpy(rlc.commands, btdev->commands, 64); cmd_complete(btdev, opcode, &rlc, sizeof(rlc)); break; case BT_HCI_CMD_READ_LOCAL_FEATURES: rlf.status = BT_HCI_ERR_SUCCESS; memcpy(rlf.features, btdev->features, 8); cmd_complete(btdev, opcode, &rlf, sizeof(rlf)); break; case BT_HCI_CMD_READ_LOCAL_EXT_FEATURES: page = ((const uint8_t *) data)[sizeof(*hdr)]; switch (page) { case 0x00: rlef.status = BT_HCI_ERR_SUCCESS; rlef.page = 0x00; rlef.max_page = 0x01; memcpy(rlef.features, btdev->features, 8); break; case 0x01: rlef.status = BT_HCI_ERR_SUCCESS; rlef.page = 0x01; rlef.max_page = 0x01; memset(rlef.features, 0, 8); if (btdev->simple_pairing_mode) rlef.features[0] |= 0x01; if (btdev->le_supported) rlef.features[0] |= 0x02; if (btdev->le_simultaneous) rlef.features[0] |= 0x04; break; default: rlef.status = BT_HCI_ERR_INVALID_PARAMETERS; rlef.page = page; rlef.max_page = 0x01; memset(rlef.features, 0, 8); break; } cmd_complete(btdev, opcode, &rlef, sizeof(rlef)); break; case BT_HCI_CMD_READ_BUFFER_SIZE: rbs.status = BT_HCI_ERR_SUCCESS; rbs.acl_mtu = cpu_to_le16(btdev->acl_mtu); rbs.sco_mtu = 0; rbs.acl_max_pkt = cpu_to_le16(btdev->acl_max_pkt); rbs.sco_max_pkt = cpu_to_le16(0); cmd_complete(btdev, opcode, &rbs, sizeof(rbs)); break; case BT_HCI_CMD_READ_COUNTRY_CODE: rcc.status = BT_HCI_ERR_SUCCESS; rcc.code = btdev->country_code; cmd_complete(btdev, opcode, &rcc, sizeof(rcc)); break; case BT_HCI_CMD_READ_BD_ADDR: rba.status = BT_HCI_ERR_SUCCESS; memcpy(rba.bdaddr, btdev->bdaddr, 6); cmd_complete(btdev, opcode, &rba, sizeof(rba)); break; case BT_HCI_CMD_READ_DATA_BLOCK_SIZE: rdbs.status = BT_HCI_ERR_SUCCESS; rdbs.max_acl_len = cpu_to_le16(btdev->acl_mtu); rdbs.block_len = cpu_to_le16(btdev->acl_mtu); rdbs.num_blocks = cpu_to_le16(btdev->acl_max_pkt); cmd_complete(btdev, opcode, &rdbs, sizeof(rdbs)); break; case BT_HCI_CMD_LE_SET_EVENT_MASK: lsem = data + sizeof(*hdr); memcpy(btdev->le_event_mask, lsem->mask, 8); status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_READ_BUFFER_SIZE: lrbs.status = BT_HCI_ERR_SUCCESS; lrbs.le_mtu = cpu_to_le16(btdev->acl_mtu); lrbs.le_max_pkt = btdev->acl_max_pkt; cmd_complete(btdev, opcode, &lrbs, sizeof(lrbs)); break; case BT_HCI_CMD_LE_READ_LOCAL_FEATURES: lrlf.status = BT_HCI_ERR_SUCCESS; memcpy(lrlf.features, btdev->le_features, 8); cmd_complete(btdev, opcode, &lrlf, sizeof(lrlf)); break; case BT_HCI_CMD_LE_SET_SCAN_PARAMETERS: status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_SET_SCAN_ENABLE: status = BT_HCI_ERR_SUCCESS; cmd_complete(btdev, opcode, &status, sizeof(status)); break; case BT_HCI_CMD_LE_READ_SUPPORTED_STATES: lrss.status = BT_HCI_ERR_SUCCESS; memcpy(lrss.states, btdev->le_states, 8); cmd_complete(btdev, opcode, &lrss, sizeof(lrss)); break; default: printf("Unsupported command 0x%4.4x\n", opcode); hexdump(data, len); cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode); break; } } void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len) { uint8_t pkt_type; if (!btdev) return; if (len < 1) return; pkt_type = ((const uint8_t *) data)[0]; switch (pkt_type) { case BT_H4_CMD_PKT: process_cmd(btdev, data + 1, len - 1); break; case BT_H4_ACL_PKT: if (btdev->conn) send_packet(btdev->conn, data, len); num_completed_packets(btdev); break; default: printf("Unsupported packet 0x%2.2x\n", pkt_type); break; } } bluez-4.101/emulator/btdev.h0000644000000000000000000000241711766125764012657 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include typedef void (*btdev_send_func) (const void *data, uint16_t len, void *user_data); struct btdev; struct btdev *btdev_create(uint16_t id); void btdev_destroy(struct btdev *btdev); void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler, void *user_data); void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len); bluez-4.101/emulator/main.c0000644000000000000000000000332711766125764012473 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "mainloop.h" #include "server.h" #include "vhci.h" static void signal_callback(int signum, void *user_data) { switch (signum) { case SIGINT: case SIGTERM: mainloop_quit(); break; } } int main(int argc, char *argv[]) { struct vhci *vhci; struct server *server; sigset_t mask; mainloop_init(); sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); mainloop_set_signal(&mask, signal_callback, NULL, NULL); vhci = vhci_open(VHCI_TYPE_BREDR, 0x23); if (!vhci) { fprintf(stderr, "Failed to open Virtual HCI device\n"); return 1; } server = server_open_unix("/tmp/bt-server-bredr", 0x42); if (!server) { fprintf(stderr, "Failed to open server channel\n"); vhci_close(vhci); return 1; } return mainloop_run(); } bluez-4.101/emulator/vhci.c0000644000000000000000000000522111766125764012473 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "mainloop.h" #include "btdev.h" #include "vhci.h" struct vhci { enum vhci_type type; int fd; struct btdev *btdev; }; static void vhci_destroy(void *user_data) { struct vhci *vhci = user_data; btdev_destroy(vhci->btdev); close(vhci->fd); free(vhci); } static void vhci_write_callback(const void *data, uint16_t len, void *user_data) { struct vhci *vhci = user_data; ssize_t written; written = write(vhci->fd, data, len); if (written < 0) return; } static void vhci_read_callback(int fd, uint32_t events, void *user_data) { struct vhci *vhci = user_data; unsigned char buf[4096]; ssize_t len; if (events & (EPOLLERR | EPOLLHUP)) return; len = read(vhci->fd, buf, sizeof(buf)); if (len < 0) return; btdev_receive_h4(vhci->btdev, buf, len); } struct vhci *vhci_open(enum vhci_type type, uint16_t id) { struct vhci *vhci; switch (type) { case VHCI_TYPE_BREDR: break; case VHCI_TYPE_AMP: return NULL; } vhci = malloc(sizeof(*vhci)); if (!vhci) return NULL; memset(vhci, 0, sizeof(*vhci)); vhci->type = type; vhci->fd = open("/dev/vhci", O_RDWR | O_NONBLOCK); if (vhci->fd < 0) { free(vhci); return NULL; } vhci->btdev = btdev_create(id); if (!vhci->btdev) { close(vhci->fd); free(vhci); return NULL; } btdev_set_send_handler(vhci->btdev, vhci_write_callback, vhci); if (mainloop_add_fd(vhci->fd, EPOLLIN, vhci_read_callback, vhci, vhci_destroy) < 0) { btdev_destroy(vhci->btdev); close(vhci->fd); free(vhci); return NULL; } return vhci; } void vhci_close(struct vhci *vhci) { if (!vhci) return; mainloop_remove_fd(vhci->fd); } bluez-4.101/emulator/server.h0000644000000000000000000000203411766125764013054 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011-2012 Intel Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include struct server; struct server *server_open_unix(const char *path, uint16_t id); void server_close(struct server *server); bluez-4.101/aclocal.m40000644000000000000000000126665611771117500011415 00000000000000# generated automatically by aclocal 1.11.3 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, # Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically `autoreconf'.])]) # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. m4_define([_LT_COPYING], [dnl # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. ]) # serial 57 LT_INIT # LT_PREREQ(VERSION) # ------------------ # Complain and exit if this libtool version is less that VERSION. m4_defun([LT_PREREQ], [m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1, [m4_default([$3], [m4_fatal([Libtool version $1 or higher is required], 63)])], [$2])]) # _LT_CHECK_BUILDDIR # ------------------ # Complain if the absolute build directory name contains unusual characters m4_defun([_LT_CHECK_BUILDDIR], [case `pwd` in *\ * | *\ *) AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;; esac ]) # LT_INIT([OPTIONS]) # ------------------ AC_DEFUN([LT_INIT], [AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl AC_BEFORE([$0], [LT_LANG])dnl AC_BEFORE([$0], [LT_OUTPUT])dnl AC_BEFORE([$0], [LTDL_INIT])dnl m4_require([_LT_CHECK_BUILDDIR])dnl dnl Autoconf doesn't catch unexpanded LT_ macros by default: m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4 dnl unless we require an AC_DEFUNed macro: AC_REQUIRE([LTOPTIONS_VERSION])dnl AC_REQUIRE([LTSUGAR_VERSION])dnl AC_REQUIRE([LTVERSION_VERSION])dnl AC_REQUIRE([LTOBSOLETE_VERSION])dnl m4_require([_LT_PROG_LTMAIN])dnl _LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}]) dnl Parse OPTIONS _LT_SET_OPTIONS([$0], [$1]) # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' AC_SUBST(LIBTOOL)dnl _LT_SETUP # Only expand once: m4_define([LT_INIT]) ])# LT_INIT # Old names: AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT]) AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PROG_LIBTOOL], []) dnl AC_DEFUN([AM_PROG_LIBTOOL], []) # _LT_CC_BASENAME(CC) # ------------------- # Calculate cc_basename. Skip known compiler wrappers and cross-prefix. m4_defun([_LT_CC_BASENAME], [for cc_temp in $1""; do case $cc_temp in compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;; distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` ]) # _LT_FILEUTILS_DEFAULTS # ---------------------- # It is okay to use these file commands and assume they have been set # sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'. m4_defun([_LT_FILEUTILS_DEFAULTS], [: ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} ])# _LT_FILEUTILS_DEFAULTS # _LT_SETUP # --------- m4_defun([_LT_SETUP], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl _LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl dnl _LT_DECL([], [host_alias], [0], [The host system])dnl _LT_DECL([], [host], [0])dnl _LT_DECL([], [host_os], [0])dnl dnl _LT_DECL([], [build_alias], [0], [The build system])dnl _LT_DECL([], [build], [0])dnl _LT_DECL([], [build_os], [0])dnl dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl dnl AC_REQUIRE([AC_PROG_LN_S])dnl test -z "$LN_S" && LN_S="ln -s" _LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl dnl AC_REQUIRE([LT_CMD_MAX_LEN])dnl _LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl _LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl m4_require([_LT_CMD_RELOAD])dnl m4_require([_LT_CHECK_MAGIC_METHOD])dnl m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl m4_require([_LT_CMD_OLD_ARCHIVE])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_WITH_SYSROOT])dnl _LT_CONFIG_LIBTOOL_INIT([ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi ]) if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi _LT_CHECK_OBJDIR m4_require([_LT_TAG_COMPILER])dnl case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o _LT_CC_BASENAME([$compiler]) # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then _LT_PATH_MAGIC fi ;; esac # Use C for the default configuration in the libtool script LT_SUPPORTED_TAG([CC]) _LT_LANG_C_CONFIG _LT_LANG_DEFAULT_CONFIG _LT_CONFIG_COMMANDS ])# _LT_SETUP # _LT_PREPARE_SED_QUOTE_VARS # -------------------------- # Define a few sed substitution that help us do robust quoting. m4_defun([_LT_PREPARE_SED_QUOTE_VARS], [# Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\([["`$\\]]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\([["`\\]]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ]) # _LT_PROG_LTMAIN # --------------- # Note that this code is called both from `configure', and `config.status' # now that we use AC_CONFIG_COMMANDS to generate libtool. Notably, # `config.status' has no value for ac_aux_dir unless we are using Automake, # so we pass a copy along to make sure it has a sensible value anyway. m4_defun([_LT_PROG_LTMAIN], [m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl _LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir']) ltmain="$ac_aux_dir/ltmain.sh" ])# _LT_PROG_LTMAIN # So that we can recreate a full libtool script including additional # tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS # in macros and then make a single call at the end using the `libtool' # label. # _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS]) # ---------------------------------------- # Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL_INIT], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_INIT], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_INIT]) # _LT_CONFIG_LIBTOOL([COMMANDS]) # ------------------------------ # Register COMMANDS to be passed to AC_CONFIG_COMMANDS later. m4_define([_LT_CONFIG_LIBTOOL], [m4_ifval([$1], [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS], [$1 ])])]) # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS]) # _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS]) # ----------------------------------------------------- m4_defun([_LT_CONFIG_SAVE_COMMANDS], [_LT_CONFIG_LIBTOOL([$1]) _LT_CONFIG_LIBTOOL_INIT([$2]) ]) # _LT_FORMAT_COMMENT([COMMENT]) # ----------------------------- # Add leading comment marks to the start of each line, and a trailing # full-stop to the whole comment if one is not present already. m4_define([_LT_FORMAT_COMMENT], [m4_ifval([$1], [ m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])], [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.]) )]) # _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?]) # ------------------------------------------------------------------- # CONFIGNAME is the name given to the value in the libtool script. # VARNAME is the (base) name used in the configure script. # VALUE may be 0, 1 or 2 for a computed quote escaped value based on # VARNAME. Any other value will be used directly. m4_define([_LT_DECL], [lt_if_append_uniq([lt_decl_varnames], [$2], [, ], [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name], [m4_ifval([$1], [$1], [$2])]) lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3]) m4_ifval([$4], [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])]) lt_dict_add_subkey([lt_decl_dict], [$2], [tagged?], [m4_ifval([$5], [yes], [no])])]) ]) # _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION]) # -------------------------------------------------------- m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])]) # lt_decl_tag_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_tag_varnames], [_lt_decl_filter([tagged?], [yes], $@)]) # _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..]) # --------------------------------------------------------- m4_define([_lt_decl_filter], [m4_case([$#], [0], [m4_fatal([$0: too few arguments: $#])], [1], [m4_fatal([$0: too few arguments: $#: $1])], [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)], [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)], [lt_dict_filter([lt_decl_dict], $@)])[]dnl ]) # lt_decl_quote_varnames([SEPARATOR], [VARNAME1...]) # -------------------------------------------------- m4_define([lt_decl_quote_varnames], [_lt_decl_filter([value], [1], $@)]) # lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_dquote_varnames], [_lt_decl_filter([value], [2], $@)]) # lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...]) # --------------------------------------------------- m4_define([lt_decl_varnames_tagged], [m4_assert([$# <= 2])dnl _$0(m4_quote(m4_default([$1], [[, ]])), m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]), m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))]) m4_define([_lt_decl_varnames_tagged], [m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])]) # lt_decl_all_varnames([SEPARATOR], [VARNAME1...]) # ------------------------------------------------ m4_define([lt_decl_all_varnames], [_$0(m4_quote(m4_default([$1], [[, ]])), m4_if([$2], [], m4_quote(lt_decl_varnames), m4_quote(m4_shift($@))))[]dnl ]) m4_define([_lt_decl_all_varnames], [lt_join($@, lt_decl_varnames_tagged([$1], lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl ]) # _LT_CONFIG_STATUS_DECLARE([VARNAME]) # ------------------------------------ # Quote a variable value, and forward it to `config.status' so that its # declaration there will have the same value as in `configure'. VARNAME # must have a single quote delimited value for this to work. m4_define([_LT_CONFIG_STATUS_DECLARE], [$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`']) # _LT_CONFIG_STATUS_DECLARATIONS # ------------------------------ # We delimit libtool config variables with single quotes, so when # we write them to config.status, we have to be sure to quote all # embedded single quotes properly. In configure, this macro expands # each variable declared with _LT_DECL (and _LT_TAGDECL) into: # # ='`$ECHO "$" | $SED "$delay_single_quote_subst"`' m4_defun([_LT_CONFIG_STATUS_DECLARATIONS], [m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames), [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAGS # ---------------- # Output comment and list of tags supported by the script m4_defun([_LT_LIBTOOL_TAGS], [_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl available_tags="_LT_TAGS"dnl ]) # _LT_LIBTOOL_DECLARE(VARNAME, [TAG]) # ----------------------------------- # Extract the dictionary values for VARNAME (optionally with TAG) and # expand to a commented shell variable setting: # # # Some comment about what VAR is for. # visible_name=$lt_internal_name m4_define([_LT_LIBTOOL_DECLARE], [_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [description])))[]dnl m4_pushdef([_libtool_name], m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])), [0], [_libtool_name=[$]$1], [1], [_libtool_name=$lt_[]$1], [2], [_libtool_name=$lt_[]$1], [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl ]) # _LT_LIBTOOL_CONFIG_VARS # ----------------------- # Produce commented declarations of non-tagged libtool config variables # suitable for insertion in the LIBTOOL CONFIG section of the `libtool' # script. Tagged libtool config variables (even for the LIBTOOL CONFIG # section) are produced by _LT_LIBTOOL_TAG_VARS. m4_defun([_LT_LIBTOOL_CONFIG_VARS], [m4_foreach([_lt_var], m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])]) # _LT_LIBTOOL_TAG_VARS(TAG) # ------------------------- m4_define([_LT_LIBTOOL_TAG_VARS], [m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames), [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])]) # _LT_TAGVAR(VARNAME, [TAGNAME]) # ------------------------------ m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])]) # _LT_CONFIG_COMMANDS # ------------------- # Send accumulated output to $CONFIG_STATUS. Thanks to the lists of # variables for single and double quote escaping we saved from calls # to _LT_DECL, we can put quote escaped variables declarations # into `config.status', and then the shell code to quote escape them in # for loops in `config.status'. Finally, any additional code accumulated # from calls to _LT_CONFIG_LIBTOOL_INIT is expanded. m4_defun([_LT_CONFIG_COMMANDS], [AC_PROVIDE_IFELSE([LT_OUTPUT], dnl If the libtool generation code has been placed in $CONFIG_LT, dnl instead of duplicating it all over again into config.status, dnl then we will have config.status run $CONFIG_LT later, so it dnl needs to know what name is stored there: [AC_CONFIG_COMMANDS([libtool], [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])], dnl If the libtool generation code is destined for config.status, dnl expand the accumulated commands and init code now: [AC_CONFIG_COMMANDS([libtool], [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])]) ])#_LT_CONFIG_COMMANDS # Initialize. m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT], [ # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' _LT_CONFIG_STATUS_DECLARATIONS LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$[]1 _LTECHO_EOF' } # Quote evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_quote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in lt_decl_all_varnames([[ \ ]], lt_decl_dquote_varnames); do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[[\\\\\\\`\\"\\\$]]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done _LT_OUTPUT_LIBTOOL_INIT ]) # _LT_GENERATED_FILE_INIT(FILE, [COMMENT]) # ------------------------------------ # Generate a child script FILE with all initialization necessary to # reuse the environment learned by the parent script, and make the # file executable. If COMMENT is supplied, it is inserted after the # `#!' sequence but before initialization text begins. After this # macro, additional text can be appended to FILE to form the body of # the child script. The macro ends with non-zero status if the # file could not be fully written (such as if the disk is full). m4_ifdef([AS_INIT_GENERATED], [m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])], [m4_defun([_LT_GENERATED_FILE_INIT], [m4_require([AS_PREPARE])]dnl [m4_pushdef([AS_MESSAGE_LOG_FD])]dnl [lt_write_fail=0 cat >$1 <<_ASEOF || lt_write_fail=1 #! $SHELL # Generated by $as_me. $2 SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$1 <<\_ASEOF || lt_write_fail=1 AS_SHELL_SANITIZE _AS_PREPARE exec AS_MESSAGE_FD>&1 _ASEOF test $lt_write_fail = 0 && chmod +x $1[]dnl m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT # LT_OUTPUT # --------- # This macro allows early generation of the libtool script (before # AC_OUTPUT is called), incase it is used in configure for compilation # tests. AC_DEFUN([LT_OUTPUT], [: ${CONFIG_LT=./config.lt} AC_MSG_NOTICE([creating $CONFIG_LT]) _LT_GENERATED_FILE_INIT(["$CONFIG_LT"], [# Run this file to recreate a libtool stub with the current configuration.]) cat >>"$CONFIG_LT" <<\_LTEOF lt_cl_silent=false exec AS_MESSAGE_LOG_FD>>config.log { echo AS_BOX([Running $as_me.]) } >&AS_MESSAGE_LOG_FD lt_cl_help="\ \`$as_me' creates a local libtool stub from the current configuration, for use in further configure time tests before the real libtool is generated. Usage: $[0] [[OPTIONS]] -h, --help print this help, then exit -V, --version print version number, then exit -q, --quiet do not print progress messages -d, --debug don't remove temporary files Report bugs to ." lt_cl_version="\ m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION]) configured by $[0], generated by m4_PACKAGE_STRING. Copyright (C) 2011 Free Software Foundation, Inc. This config.lt script is free software; the Free Software Foundation gives unlimited permision to copy, distribute and modify it." while test $[#] != 0 do case $[1] in --version | --v* | -V ) echo "$lt_cl_version"; exit 0 ;; --help | --h* | -h ) echo "$lt_cl_help"; exit 0 ;; --debug | --d* | -d ) debug=: ;; --quiet | --q* | --silent | --s* | -q ) lt_cl_silent=: ;; -*) AC_MSG_ERROR([unrecognized option: $[1] Try \`$[0] --help' for more information.]) ;; *) AC_MSG_ERROR([unrecognized argument: $[1] Try \`$[0] --help' for more information.]) ;; esac shift done if $lt_cl_silent; then exec AS_MESSAGE_FD>/dev/null fi _LTEOF cat >>"$CONFIG_LT" <<_LTEOF _LT_OUTPUT_LIBTOOL_COMMANDS_INIT _LTEOF cat >>"$CONFIG_LT" <<\_LTEOF AC_MSG_NOTICE([creating $ofile]) _LT_OUTPUT_LIBTOOL_COMMANDS AS_EXIT(0) _LTEOF chmod +x "$CONFIG_LT" # configure is writing to config.log, but config.lt does its own redirection, # appending to config.log, which fails on DOS, as config.log is still kept # open by configure. Here we exec the FD to /dev/null, effectively closing # config.log, so it can be properly (re)opened and appended to by config.lt. lt_cl_success=: test "$silent" = yes && lt_config_lt_args="$lt_config_lt_args --quiet" exec AS_MESSAGE_LOG_FD>/dev/null $SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false exec AS_MESSAGE_LOG_FD>>config.log $lt_cl_success || AS_EXIT(1) ])# LT_OUTPUT # _LT_CONFIG(TAG) # --------------- # If TAG is the built-in tag, create an initial libtool script with a # default configuration from the untagged config vars. Otherwise add code # to config.status for appending the configuration named by TAG from the # matching tagged config vars. m4_defun([_LT_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_CONFIG_SAVE_COMMANDS([ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl m4_if(_LT_TAG, [C], [ # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # _LT_COPYING _LT_LIBTOOL_TAGS # ### BEGIN LIBTOOL CONFIG _LT_LIBTOOL_CONFIG_VARS _LT_LIBTOOL_TAG_VARS # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac _LT_PROG_LTMAIN # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) _LT_PROG_REPLACE_SHELLFNS mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ], [cat <<_LT_EOF >> "$ofile" dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded dnl in a comment (ie after a #). # ### BEGIN LIBTOOL TAG CONFIG: $1 _LT_LIBTOOL_TAG_VARS(_LT_TAG) # ### END LIBTOOL TAG CONFIG: $1 _LT_EOF ])dnl /m4_if ], [m4_if([$1], [], [ PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile'], []) ])dnl /_LT_CONFIG_SAVE_COMMANDS ])# _LT_CONFIG # LT_SUPPORTED_TAG(TAG) # --------------------- # Trace this macro to discover what tags are supported by the libtool # --tag option, using: # autoconf --trace 'LT_SUPPORTED_TAG:$1' AC_DEFUN([LT_SUPPORTED_TAG], []) # C support is built-in for now m4_define([_LT_LANG_C_enabled], []) m4_define([_LT_TAGS], []) # LT_LANG(LANG) # ------------- # Enable libtool support for the given language if not already enabled. AC_DEFUN([LT_LANG], [AC_BEFORE([$0], [LT_OUTPUT])dnl m4_case([$1], [C], [_LT_LANG(C)], [C++], [_LT_LANG(CXX)], [Go], [_LT_LANG(GO)], [Java], [_LT_LANG(GCJ)], [Fortran 77], [_LT_LANG(F77)], [Fortran], [_LT_LANG(FC)], [Windows Resource], [_LT_LANG(RC)], [m4_ifdef([_LT_LANG_]$1[_CONFIG], [_LT_LANG($1)], [m4_fatal([$0: unsupported language: "$1"])])])dnl ])# LT_LANG # _LT_LANG(LANGNAME) # ------------------ m4_defun([_LT_LANG], [m4_ifdef([_LT_LANG_]$1[_enabled], [], [LT_SUPPORTED_TAG([$1])dnl m4_append([_LT_TAGS], [$1 ])dnl m4_define([_LT_LANG_]$1[_enabled], [])dnl _LT_LANG_$1_CONFIG($1)])dnl ])# _LT_LANG m4_ifndef([AC_PROG_GO], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_GO. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_GO], [AC_LANG_PUSH(Go)dnl AC_ARG_VAR([GOC], [Go compiler command])dnl AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl _AC_ARG_VAR_LDFLAGS()dnl AC_CHECK_TOOL(GOC, gccgo) if test -z "$GOC"; then if test -n "$ac_tool_prefix"; then AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo]) fi fi if test -z "$GOC"; then AC_CHECK_PROG(GOC, gccgo, gccgo, false) fi ])#m4_defun ])#m4_ifndef # _LT_LANG_DEFAULT_CONFIG # ----------------------- m4_defun([_LT_LANG_DEFAULT_CONFIG], [AC_PROVIDE_IFELSE([AC_PROG_CXX], [LT_LANG(CXX)], [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])]) AC_PROVIDE_IFELSE([AC_PROG_F77], [LT_LANG(F77)], [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])]) AC_PROVIDE_IFELSE([AC_PROG_FC], [LT_LANG(FC)], [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])]) dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal dnl pulling things in needlessly. AC_PROVIDE_IFELSE([AC_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([A][M_PROG_GCJ], [LT_LANG(GCJ)], [AC_PROVIDE_IFELSE([LT_PROG_GCJ], [LT_LANG(GCJ)], [m4_ifdef([AC_PROG_GCJ], [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([A][M_PROG_GCJ], [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])]) m4_ifdef([LT_PROG_GCJ], [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])]) AC_PROVIDE_IFELSE([AC_PROG_GO], [LT_LANG(GO)], [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])]) AC_PROVIDE_IFELSE([LT_PROG_RC], [LT_LANG(RC)], [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])]) ])# _LT_LANG_DEFAULT_CONFIG # Obsolete macros: AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)]) AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)]) AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)]) AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)]) AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_CXX], []) dnl AC_DEFUN([AC_LIBTOOL_F77], []) dnl AC_DEFUN([AC_LIBTOOL_FC], []) dnl AC_DEFUN([AC_LIBTOOL_GCJ], []) dnl AC_DEFUN([AC_LIBTOOL_RC], []) # _LT_TAG_COMPILER # ---------------- m4_defun([_LT_TAG_COMPILER], [AC_REQUIRE([AC_PROG_CC])dnl _LT_DECL([LTCC], [CC], [1], [A C compiler])dnl _LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl _LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl _LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC ])# _LT_TAG_COMPILER # _LT_COMPILER_BOILERPLATE # ------------------------ # Check for compiler boilerplate output or warnings with # the simple compiler test code. m4_defun([_LT_COMPILER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ])# _LT_COMPILER_BOILERPLATE # _LT_LINKER_BOILERPLATE # ---------------------- # Check for linker boilerplate output or warnings with # the simple link test code. m4_defun([_LT_LINKER_BOILERPLATE], [m4_require([_LT_DECL_SED])dnl ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* ])# _LT_LINKER_BOILERPLATE # _LT_REQUIRED_DARWIN_CHECKS # ------------------------- m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[ case $host_os in rhapsody* | darwin*) AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:]) AC_CHECK_TOOL([NMEDIT], [nmedit], [:]) AC_CHECK_TOOL([LIPO], [lipo], [:]) AC_CHECK_TOOL([OTOOL], [otool], [:]) AC_CHECK_TOOL([OTOOL64], [otool64], [:]) _LT_DECL([], [DSYMUTIL], [1], [Tool to manipulate archived DWARF debug symbol files on Mac OS X]) _LT_DECL([], [NMEDIT], [1], [Tool to change global to local symbols on Mac OS X]) _LT_DECL([], [LIPO], [1], [Tool to manipulate fat objects and archives on Mac OS X]) _LT_DECL([], [OTOOL], [1], [ldd/readelf like tool for Mach-O binaries on Mac OS X]) _LT_DECL([], [OTOOL64], [1], [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4]) AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod], [lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -rf libconftest.dylib* rm -f conftest.* fi]) AC_CACHE_CHECK([for -exported_symbols_list linker flag], [lt_cv_ld_exported_symbols_list], [lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [lt_cv_ld_exported_symbols_list=yes], [lt_cv_ld_exported_symbols_list=no]) LDFLAGS="$save_LDFLAGS" ]) AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load], [lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&AS_MESSAGE_LOG_FD elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&AS_MESSAGE_LOG_FD fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM ]) case $host_os in rhapsody* | darwin1.[[012]]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[[012]]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ]) # _LT_DARWIN_LINKER_FEATURES([TAG]) # --------------------------------- # Checks for linker and compiler features on darwin m4_defun([_LT_DARWIN_LINKER_FEATURES], [ m4_require([_LT_REQUIRED_DARWIN_CHECKS]) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported if test "$lt_cv_ld_force_load" = "yes"; then _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes], [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes]) else _LT_TAGVAR(whole_archive_flag_spec, $1)='' fi _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" m4_if([$1], [CXX], [ if test "$lt_cv_apple_cc_single_mod" != "yes"; then _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}" _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}" fi ],[]) else _LT_TAGVAR(ld_shlibs, $1)=no fi ]) # _LT_SYS_MODULE_PATH_AIX([TAGNAME]) # ---------------------------------- # Links a minimal program and checks the executable # for the system default hardcoded library path. In most cases, # this is /usr/lib:/lib, but when the MPI compilers are used # the location of the communication and MPI libs are included too. # If we don't find anything, use the default library path according # to the aix ld manual. # Store the results from the different compilers for each TAGNAME. # Allow to override them for all tags through lt_cv_aix_libpath. m4_defun([_LT_SYS_MODULE_PATH_AIX], [m4_require([_LT_DECL_SED])dnl if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])], [AC_LINK_IFELSE([AC_LANG_PROGRAM],[ lt_aix_libpath_sed='[ /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }]' _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi],[]) if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib" fi ]) aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1]) fi ])# _LT_SYS_MODULE_PATH_AIX # _LT_SHELL_INIT(ARG) # ------------------- m4_define([_LT_SHELL_INIT], [m4_divert_text([M4SH-INIT], [$1 ])])# _LT_SHELL_INIT # _LT_PROG_ECHO_BACKSLASH # ----------------------- # Find how we can fake an echo command that does not interpret backslash. # In particular, with Autoconf 2.60 or later we add some code to the start # of the generated configure script which will find a shell with a builtin # printf (which we can use as an echo command). m4_defun([_LT_PROG_ECHO_BACKSLASH], [ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO AC_MSG_CHECKING([how to print strings]) # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $[]1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "$*" } case "$ECHO" in printf*) AC_MSG_RESULT([printf]) ;; print*) AC_MSG_RESULT([print -r]) ;; *) AC_MSG_RESULT([cat]) ;; esac m4_ifdef([_AS_DETECT_SUGGESTED], [_AS_DETECT_SUGGESTED([ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test "X`printf %s $ECHO`" = "X$ECHO" \ || test "X`print -r -- $ECHO`" = "X$ECHO" )])]) _LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts]) _LT_DECL([], [ECHO], [1], [An echo program that protects backslashes]) ])# _LT_PROG_ECHO_BACKSLASH # _LT_WITH_SYSROOT # ---------------- AC_DEFUN([_LT_WITH_SYSROOT], [AC_MSG_CHECKING([for sysroot]) AC_ARG_WITH([sysroot], [ --with-sysroot[=DIR] Search for dependent libraries within DIR (or the compiler's sysroot if not specified).], [], [with_sysroot=no]) dnl lt_sysroot will always be passed unquoted. We quote it here dnl in case the user passed a directory name. lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) AC_MSG_RESULT([${with_sysroot}]) AC_MSG_ERROR([The sysroot must be an absolute path.]) ;; esac AC_MSG_RESULT([${lt_sysroot:-no}]) _LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl [dependent libraries, and in which our libraries should be installed.])]) # _LT_ENABLE_LOCK # --------------- m4_defun([_LT_ENABLE_LOCK], [AC_ARG_ENABLE([libtool-lock], [AS_HELP_STRING([--disable-libtool-lock], [avoid locking (might break parallel builds)])]) test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf, [AC_LANG_PUSH(C) AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no]) AC_LANG_POP]) if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if AC_TRY_EVAL(ac_compile); then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" ])# _LT_ENABLE_LOCK # _LT_PROG_AR # ----------- m4_defun([_LT_PROG_AR], [AC_CHECK_TOOLS(AR, [ar], false) : ${AR=ar} : ${AR_FLAGS=cru} _LT_DECL([], [AR], [1], [The archiver]) _LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive]) AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file], [lt_cv_ar_at_file=no AC_COMPILE_IFELSE([AC_LANG_PROGRAM], [echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD' AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a AC_TRY_EVAL([lt_ar_try]) if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a ]) ]) if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi _LT_DECL([], [archiver_list_spec], [1], [How to feed a file listing to the archiver]) ])# _LT_PROG_AR # _LT_CMD_OLD_ARCHIVE # ------------------- m4_defun([_LT_CMD_OLD_ARCHIVE], [_LT_PROG_AR AC_CHECK_TOOL(STRIP, strip, :) test -z "$STRIP" && STRIP=: _LT_DECL([], [STRIP], [1], [A symbol stripping program]) AC_CHECK_TOOL(RANLIB, ranlib, :) test -z "$RANLIB" && RANLIB=: _LT_DECL([], [RANLIB], [1], [Commands used to install an old-style archive]) # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac _LT_DECL([], [old_postinstall_cmds], [2]) _LT_DECL([], [old_postuninstall_cmds], [2]) _LT_TAGDECL([], [old_archive_cmds], [2], [Commands used to build an old-style archive]) _LT_DECL([], [lock_old_archive_extraction], [0], [Whether to use a lock for old archive extraction]) ])# _LT_CMD_OLD_ARCHIVE # _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------------------- # Check whether the given compiler option works AC_DEFUN([_LT_COMPILER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4]) echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$3" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi fi $RM conftest* ]) if test x"[$]$2" = xyes; then m4_if([$5], , :, [$5]) else m4_if([$6], , :, [$6]) fi ])# _LT_COMPILER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], []) # _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS, # [ACTION-SUCCESS], [ACTION-FAILURE]) # ---------------------------------------------------- # Check whether the given linker option works AC_DEFUN([_LT_LINKER_OPTION], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_SED])dnl AC_CACHE_CHECK([$1], [$2], [$2=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $3" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&AS_MESSAGE_LOG_FD $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then $2=yes fi else $2=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" ]) if test x"[$]$2" = xyes; then m4_if([$4], , :, [$4]) else m4_if([$5], , :, [$5]) fi ])# _LT_LINKER_OPTION # Old name: AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], []) # LT_CMD_MAX_LEN #--------------- AC_DEFUN([LT_CMD_MAX_LEN], [AC_REQUIRE([AC_CANONICAL_HOST])dnl # find the maximum length of command line arguments AC_MSG_CHECKING([the maximum length of command line arguments]) AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac ]) if test -n $lt_cv_sys_max_cmd_len ; then AC_MSG_RESULT($lt_cv_sys_max_cmd_len) else AC_MSG_RESULT(none) fi max_cmd_len=$lt_cv_sys_max_cmd_len _LT_DECL([], [max_cmd_len], [0], [What is the maximum length of a command?]) ])# LT_CMD_MAX_LEN # Old name: AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], []) # _LT_HEADER_DLFCN # ---------------- m4_defun([_LT_HEADER_DLFCN], [AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl ])# _LT_HEADER_DLFCN # _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE, # ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING) # ---------------------------------------------------------------- m4_defun([_LT_TRY_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "$cross_compiling" = yes; then : [$4] else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF [#line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; }] _LT_EOF if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) $1 ;; x$lt_dlneed_uscore) $2 ;; x$lt_dlunknown|x*) $3 ;; esac else : # compilation failed $3 fi fi rm -fr conftest* ])# _LT_TRY_DLOPEN_SELF # LT_SYS_DLOPEN_SELF # ------------------ AC_DEFUN([LT_SYS_DLOPEN_SELF], [m4_require([_LT_HEADER_DLFCN])dnl if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[ lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ]) ;; *) AC_CHECK_FUNC([shl_load], [lt_cv_dlopen="shl_load"], [AC_CHECK_LIB([dld], [shl_load], [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"], [AC_CHECK_FUNC([dlopen], [lt_cv_dlopen="dlopen"], [AC_CHECK_LIB([dl], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"], [AC_CHECK_LIB([svld], [dlopen], [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"], [AC_CHECK_LIB([dld], [dld_link], [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"]) ]) ]) ]) ]) ]) ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" AC_CACHE_CHECK([whether a program can dlopen itself], lt_cv_dlopen_self, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes, lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross) ]) if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" AC_CACHE_CHECK([whether a statically linked program can dlopen itself], lt_cv_dlopen_self_static, [dnl _LT_TRY_DLOPEN_SELF( lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross) ]) fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi _LT_DECL([dlopen_support], [enable_dlopen], [0], [Whether dlopen is supported]) _LT_DECL([dlopen_self], [enable_dlopen_self], [0], [Whether dlopen of programs is supported]) _LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0], [Whether dlopen of statically linked programs is supported]) ])# LT_SYS_DLOPEN_SELF # Old name: AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], []) # _LT_COMPILER_C_O([TAGNAME]) # --------------------------- # Check to see if options -c and -o are simultaneously supported by compiler. # This macro does not hard code the compiler like AC_PROG_CC_C_O. m4_defun([_LT_COMPILER_C_O], [m4_require([_LT_DECL_SED])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&AS_MESSAGE_LOG_FD echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes fi fi chmod u+w . 2>&AS_MESSAGE_LOG_FD $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* ]) _LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1], [Does compiler simultaneously support -c and -o options?]) ])# _LT_COMPILER_C_O # _LT_COMPILER_FILE_LOCKS([TAGNAME]) # ---------------------------------- # Check to see if we can do hard links to lock some files if needed m4_defun([_LT_COMPILER_FILE_LOCKS], [m4_require([_LT_ENABLE_LOCK])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl _LT_COMPILER_C_O([$1]) hard_links="nottested" if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user AC_MSG_CHECKING([if we can lock with hard links]) hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no AC_MSG_RESULT([$hard_links]) if test "$hard_links" = no; then AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe]) need_locks=warn fi else need_locks=no fi _LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?]) ])# _LT_COMPILER_FILE_LOCKS # _LT_CHECK_OBJDIR # ---------------- m4_defun([_LT_CHECK_OBJDIR], [AC_CACHE_CHECK([for objdir], [lt_cv_objdir], [rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null]) objdir=$lt_cv_objdir _LT_DECL([], [objdir], [0], [The name of the directory that contains temporary libtool files])dnl m4_pattern_allow([LT_OBJDIR])dnl AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/", [Define to the sub-directory in which libtool stores uninstalled libraries.]) ])# _LT_CHECK_OBJDIR # _LT_LINKER_HARDCODE_LIBPATH([TAGNAME]) # -------------------------------------- # Check hardcoding attributes. m4_defun([_LT_LINKER_HARDCODE_LIBPATH], [AC_MSG_CHECKING([how to hardcode library paths into programs]) _LT_TAGVAR(hardcode_action, $1)= if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" || test -n "$_LT_TAGVAR(runpath_var, $1)" || test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then # We can hardcode non-existent directories. if test "$_LT_TAGVAR(hardcode_direct, $1)" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no && test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then # Linking always hardcodes the temporary library directory. _LT_TAGVAR(hardcode_action, $1)=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. _LT_TAGVAR(hardcode_action, $1)=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. _LT_TAGVAR(hardcode_action, $1)=unsupported fi AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)]) if test "$_LT_TAGVAR(hardcode_action, $1)" = relink || test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi _LT_TAGDECL([], [hardcode_action], [0], [How to hardcode a shared library path into an executable]) ])# _LT_LINKER_HARDCODE_LIBPATH # _LT_CMD_STRIPLIB # ---------------- m4_defun([_LT_CMD_STRIPLIB], [m4_require([_LT_DECL_EGREP]) striplib= old_striplib= AC_MSG_CHECKING([whether stripping libraries is possible]) if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" AC_MSG_RESULT([yes]) else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi ;; *) AC_MSG_RESULT([no]) ;; esac fi _LT_DECL([], [old_striplib], [1], [Commands to strip libraries]) _LT_DECL([], [striplib], [1]) ])# _LT_CMD_STRIPLIB # _LT_SYS_DYNAMIC_LINKER([TAG]) # ----------------------------- # PORTME Fill in your ld.so characteristics m4_defun([_LT_SYS_DYNAMIC_LINKER], [AC_REQUIRE([AC_CANONICAL_HOST])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_OBJDUMP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CHECK_SHELL_FEATURES])dnl AC_MSG_CHECKING([dynamic linker characteristics]) m4_if([$1], [], [ if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[[lt_foo]]++; } if (lt_freq[[lt_foo]] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi]) library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[[4-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[[01]] | aix4.[[01]].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[[45]]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"]) ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' m4_if([$1], [],[ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"]) sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[[23]].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[[01]]* | freebsdelf3.[[01]]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[[3-9]]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath], [lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\"" AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])], [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null], [lt_cv_shlibpath_overrides_runpath=yes])]) LDFLAGS=$save_LDFLAGS libdir=$save_libdir ]) shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[[89]] | openbsd2.[[89]].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac AC_MSG_RESULT([$dynamic_linker]) test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi _LT_DECL([], [variables_saved_for_relink], [1], [Variables whose values should be saved in libtool wrapper scripts and restored at link time]) _LT_DECL([], [need_lib_prefix], [0], [Do we need the "lib" prefix for modules?]) _LT_DECL([], [need_version], [0], [Do we need a version for libraries?]) _LT_DECL([], [version_type], [0], [Library versioning type]) _LT_DECL([], [runpath_var], [0], [Shared library runtime path variable]) _LT_DECL([], [shlibpath_var], [0],[Shared library path variable]) _LT_DECL([], [shlibpath_overrides_runpath], [0], [Is shlibpath searched before the hard-coded library search path?]) _LT_DECL([], [libname_spec], [1], [Format of library name prefix]) _LT_DECL([], [library_names_spec], [1], [[List of archive names. First name is the real one, the rest are links. The last name is the one that the linker finds with -lNAME]]) _LT_DECL([], [soname_spec], [1], [[The coded name of the library, if different from the real name]]) _LT_DECL([], [install_override_mode], [1], [Permission mode override for installation of shared libraries]) _LT_DECL([], [postinstall_cmds], [2], [Command to use after installation of a shared archive]) _LT_DECL([], [postuninstall_cmds], [2], [Command to use after uninstallation of a shared archive]) _LT_DECL([], [finish_cmds], [2], [Commands used to finish a libtool library installation in a directory]) _LT_DECL([], [finish_eval], [1], [[As "finish_cmds", except a single script fragment to be evaled but not shown]]) _LT_DECL([], [hardcode_into_libs], [0], [Whether we should hardcode library paths into libraries]) _LT_DECL([], [sys_lib_search_path_spec], [2], [Compile-time system search path for libraries]) _LT_DECL([], [sys_lib_dlsearch_path_spec], [2], [Run-time system search path for libraries]) ])# _LT_SYS_DYNAMIC_LINKER # _LT_PATH_TOOL_PREFIX(TOOL) # -------------------------- # find a file program which can recognize shared library AC_DEFUN([_LT_PATH_TOOL_PREFIX], [m4_require([_LT_DECL_EGREP])dnl AC_MSG_CHECKING([for $1]) AC_CACHE_VAL(lt_cv_path_MAGIC_CMD, [case $MAGIC_CMD in [[\\/*] | ?:[\\/]*]) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR dnl $ac_dummy forces splitting on constant user-supplied paths. dnl POSIX.2 word splitting is done only on the output of word expansions, dnl not every word. This closes a longstanding sh security hole. ac_dummy="m4_if([$2], , $PATH, [$2])" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/$1; then lt_cv_path_MAGIC_CMD="$ac_dir/$1" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac]) MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then AC_MSG_RESULT($MAGIC_CMD) else AC_MSG_RESULT(no) fi _LT_DECL([], [MAGIC_CMD], [0], [Used to examine libraries when file_magic_cmd begins with "file"])dnl ])# _LT_PATH_TOOL_PREFIX # Old name: AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], []) # _LT_PATH_MAGIC # -------------- # find a file program which can recognize a shared library m4_defun([_LT_PATH_MAGIC], [_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH) if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH) else MAGIC_CMD=: fi fi ])# _LT_PATH_MAGIC # LT_PATH_LD # ---------- # find the pathname to the GNU or non-GNU linker AC_DEFUN([LT_PATH_LD], [AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PROG_ECHO_BACKSLASH])dnl AC_ARG_WITH([gnu-ld], [AS_HELP_STRING([--with-gnu-ld], [assume the C compiler uses GNU ld @<:@default=no@:>@])], [test "$withval" = no || with_gnu_ld=yes], [with_gnu_ld=no])dnl ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. AC_MSG_CHECKING([for ld used by $CC]) case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [[\\/]]* | ?:[[\\/]]*) re_direlt='/[[^/]][[^/]]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then AC_MSG_CHECKING([for GNU ld]) else AC_MSG_CHECKING([for non-GNU ld]) fi AC_CACHE_VAL(lt_cv_path_LD, [if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &1 /dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'] lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[[3-9]]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac ]) file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown _LT_DECL([], [deplibs_check_method], [1], [Method to check whether dependent libraries are shared objects]) _LT_DECL([], [file_magic_cmd], [1], [Command to use when deplibs_check_method = "file_magic"]) _LT_DECL([], [file_magic_glob], [1], [How to find potential files when deplibs_check_method = "file_magic"]) _LT_DECL([], [want_nocaseglob], [1], [Find potential files using nocaseglob when deplibs_check_method = "file_magic"]) ])# _LT_CHECK_MAGIC_METHOD # LT_PATH_NM # ---------- # find the pathname to a BSD- or MS-compatible name lister AC_DEFUN([LT_PATH_NM], [AC_REQUIRE([AC_PROG_CC])dnl AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM, [if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi]) if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :) case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi AC_SUBST([DUMPBIN]) if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm AC_SUBST([NM]) _LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface], [lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&AS_MESSAGE_LOG_FD (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD) cat conftest.out >&AS_MESSAGE_LOG_FD if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest*]) ])# LT_PATH_NM # Old names: AU_ALIAS([AM_PROG_NM], [LT_PATH_NM]) AU_ALIAS([AC_PROG_NM], [LT_PATH_NM]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_PROG_NM], []) dnl AC_DEFUN([AC_PROG_NM], []) # _LT_CHECK_SHAREDLIB_FROM_LINKLIB # -------------------------------- # how to determine the name of the shared library # associated with a specific link library. # -- PORTME fill in with the dynamic library characteristics m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB], [m4_require([_LT_DECL_EGREP]) m4_require([_LT_DECL_OBJDUMP]) m4_require([_LT_DECL_DLLTOOL]) AC_CACHE_CHECK([how to associate runtime and link libraries], lt_cv_sharedlib_from_linklib_cmd, [lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac ]) sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO _LT_DECL([], [sharedlib_from_linklib_cmd], [1], [Command to associate shared and link libraries]) ])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB # _LT_PATH_MANIFEST_TOOL # ---------------------- # locate the manifest tool m4_defun([_LT_PATH_MANIFEST_TOOL], [AC_CHECK_TOOL(MANIFEST_TOOL, mt, :) test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool], [lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&AS_MESSAGE_LOG_FD if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest*]) if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi _LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl ])# _LT_PATH_MANIFEST_TOOL # LT_LIB_M # -------- # check for math library AC_DEFUN([LT_LIB_M], [AC_REQUIRE([AC_CANONICAL_HOST])dnl LIBM= case $host in *-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*) # These system don't have libm, or don't need it ;; *-ncr-sysv4.3*) AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw") AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm") ;; *) AC_CHECK_LIB(m, cos, LIBM="-lm") ;; esac AC_SUBST([LIBM]) ])# LT_LIB_M # Old name: AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_CHECK_LIBM], []) # _LT_COMPILER_NO_RTTI([TAGNAME]) # ------------------------------- m4_defun([_LT_COMPILER_NO_RTTI], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= if test "$GCC" = yes; then case $cc_basename in nvcc*) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;; *) _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;; esac _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions], lt_cv_prog_compiler_rtti_exceptions, [-fno-rtti -fno-exceptions], [], [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"]) fi _LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1], [Compiler flag to turn off builtin functions]) ])# _LT_COMPILER_NO_RTTI # _LT_CMD_GLOBAL_SYMBOLS # ---------------------- m4_defun([_LT_CMD_GLOBAL_SYMBOLS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_PROG_CC])dnl AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([LT_PATH_NM])dnl AC_REQUIRE([LT_PATH_LD])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_TAG_COMPILER])dnl # Check for command to grab the raw symbol name followed by C symbol from nm. AC_MSG_CHECKING([command to parse $NM output from $compiler object]) AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe], [ # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[[BCDEGRST]]' # Regexp to match symbols that can be accessed directly from C. sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[[BCDT]]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[[ABCDGISTW]]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[[ABCDEGRST]]' fi ;; irix* | nonstopux*) symcode='[[BCDEGRST]]' ;; osf*) symcode='[[BCDEGQRST]]' ;; solaris*) symcode='[[BDRT]]' ;; sco3.2v5*) symcode='[[DT]]' ;; sysv4.2uw2*) symcode='[[DT]]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[[ABDT]]' ;; sysv4) symcode='[[DFNSTU]]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[[ABCDGIRSTW]]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK ['"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx]" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if AC_TRY_EVAL(ac_compile); then # Now try to grab the symbols. nlist=conftest.nm if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT@&t@_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT@&t@_DLSYM_CONST #else # define LT@&t@_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT@&t@_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[[]] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)" if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD fi else echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done ]) if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then AC_MSG_RESULT(failed) else AC_MSG_RESULT(ok) fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then nm_file_list_spec='@' fi _LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1], [Take the output of nm and produce a listing of raw symbols and C names]) _LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1], [Transform the output of nm in a proper C declaration]) _LT_DECL([global_symbol_to_c_name_address], [lt_cv_sys_global_symbol_to_c_name_address], [1], [Transform the output of nm in a C name address pair]) _LT_DECL([global_symbol_to_c_name_address_lib_prefix], [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1], [Transform the output of nm in a C name address pair when lib prefix is needed]) _LT_DECL([], [nm_file_list_spec], [1], [Specify filename containing input files for $NM]) ]) # _LT_CMD_GLOBAL_SYMBOLS # _LT_COMPILER_PIC([TAGNAME]) # --------------------------- m4_defun([_LT_COMPILER_PIC], [m4_require([_LT_TAG_COMPILER])dnl _LT_TAGVAR(lt_prog_compiler_wl, $1)= _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)= m4_if([$1], [CXX], [ # C++ specific cases for pic, static, wl, etc. if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; *djgpp*) # DJGPP does not support shared libraries at all _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac else case $host_os in aix[[4-9]]*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; chorus*) case $cc_basename in cxch68*) # Green Hills C++ Compiler # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a" ;; esac ;; mingw* | cygwin* | os2* | pw32* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; dgux*) case $cc_basename in ec++*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; ghcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; freebsd* | dragonfly*) # FreeBSD uses GNU C++ ;; hpux9* | hpux10* | hpux11*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' if test "$host_cpu" != ia64; then _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' fi ;; aCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac ;; *) ;; esac ;; interix*) # This is c89, which is MS Visual C++ (no shared libs) # Anyone wants to do a port? ;; irix5* | irix6* | nonstopux*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' # CC pic flag -KPIC is the default. ;; *) ;; esac ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # KAI C++ Compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; ecpc* ) # old Intel C++ for x86_64 which still supported -KPIC. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; icpc* ) # Intel C++, used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; pgCC* | pgcpp*) # Portland Group C++ compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; cxx*) # Compaq C++ # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL 8.0, 9.0 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; esac ;; esac ;; lynxos*) ;; m88k*) ;; mvs*) case $cc_basename in cxx*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall' ;; *) ;; esac ;; netbsd* | netbsdelf*-gnu) ;; *qnx* | *nto*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,' ;; RCC*) # Rational C++ 2.4.1 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; cxx*) # Digital/Compaq C++ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # Make sure the PIC flag is empty. It appears that all Alpha # Linux and Compaq Tru64 Unix objects are PIC. _LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; *) ;; esac ;; psos*) ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' ;; *) ;; esac ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; lcc*) # Lucid _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' ;; *) ;; esac ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) case $cc_basename in CC*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' ;; *) ;; esac ;; vxworks*) ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ], [ if test "$GCC" = yes; then _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. _LT_TAGVAR(lt_prog_compiler_static, $1)= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac ;; interix[[3-9]]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic fi ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker ' if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' else _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). m4_if([$1], [GCJ], [], [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT']) ;; hpux9* | hpux10* | hpux11*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # PIC (with -KPIC) is the default. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; # Lahey Fortran 8.1. lf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared' _LT_TAGVAR(lt_prog_compiler_static, $1)='--static' ;; nagfor*) # NAG Fortran compiler _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; ccc*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All Alpha code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='' ;; *Sun\ F* | *Sun*Fortran*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' ;; *Intel*\ [[CF]]*Compiler*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-static' ;; *Portland\ Group*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; esac ;; esac ;; newsos6) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared' ;; osf3* | osf4* | osf5*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' # All OSF/1 code is PIC. _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; rdos*) _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared' ;; solaris*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';; *) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';; esac ;; sunos4*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; unicos*) _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,' _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; uts4*) _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic' _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic' ;; *) _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no ;; esac fi ]) case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) _LT_TAGVAR(lt_prog_compiler_pic, $1)= ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])" ;; esac AC_CACHE_CHECK([for $compiler option to produce PIC], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)], [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)]) _LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1) # # Check to make sure the PIC flag actually works. # if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works], [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)], [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [], [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in "" | " "*) ;; *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;; esac], [_LT_TAGVAR(lt_prog_compiler_pic, $1)= _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no]) fi _LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1], [Additional compiler flags for building library objects]) _LT_TAGDECL([wl], [lt_prog_compiler_wl], [1], [How to pass a linker flag through the compiler]) # # Check to make sure the static flag actually works. # wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\" _LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works], _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1), $lt_tmp_static_flag, [], [_LT_TAGVAR(lt_prog_compiler_static, $1)=]) _LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1], [Compiler flag to prevent dynamic linking]) ])# _LT_COMPILER_PIC # _LT_LINKER_SHLIBS([TAGNAME]) # ---------------------------- # See if the linker supports building shared libraries. m4_defun([_LT_LINKER_SHLIBS], [AC_REQUIRE([LT_PATH_LD])dnl AC_REQUIRE([LT_PATH_NM])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_DECL_SED])dnl m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl m4_require([_LT_TAG_COMPILER])dnl AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) m4_if([$1], [CXX], [ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] case $host_os in aix[[4-9]]*) # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global defined # symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi ;; pw32*) _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds" ;; cygwin* | mingw* | cegcc*) case $cc_basename in cl*) _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] ;; esac ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; *) _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' ;; esac ], [ runpath_var= _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_cmds, $1)= _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(old_archive_from_new_cmds, $1)= _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)= _LT_TAGVAR(thread_safe_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list _LT_TAGVAR(include_expsyms, $1)= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'] # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. dnl Note also adjust exclude_expsyms for C++ above. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) _LT_TAGVAR(link_all_deplibs, $1)=no ;; esac _LT_TAGVAR(ld_shlibs, $1)=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;; *\ \(GNU\ Binutils\)\ [[3-9]]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[[3-9]]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols' _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'] if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 _LT_TAGVAR(whole_archive_flag_spec, $1)= tmp_sharedflag='--shared' ;; xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*) _LT_TAGVAR(ld_shlibs, $1)=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; sunos4*) _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then runpath_var= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. _LT_TAGVAR(hardcode_minus_L, $1)=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. _LT_TAGVAR(hardcode_direct, $1)=unsupported fi ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi _LT_TAGVAR(link_all_deplibs, $1)=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='' ;; m68k) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac ;; bsdi[[45]]*) _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' # FIXME: Should let the user specify the lib program. _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; hpux9*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) m4_if($1, [], [ # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) _LT_LINKER_OPTION([if $CC understands -b], _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'], [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])], [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags']) ;; esac fi if test "$with_gnu_ld" = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. _LT_TAGVAR(hardcode_minus_L, $1)=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol], [lt_cv_irix_exported_symbol], [save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" AC_LINK_IFELSE( [AC_LANG_SOURCE( [AC_LANG_CASE([C], [[int foo (void) { return 0; }]], [C++], [[int foo (void) { return 0; }]], [Fortran 77], [[ subroutine foo end]], [Fortran], [[ subroutine foo end]])])], [lt_cv_irix_exported_symbol=yes], [lt_cv_irix_exported_symbol=no]) LDFLAGS="$save_LDFLAGS"]) if test "$lt_cv_irix_exported_symbol" = yes; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes _LT_TAGVAR(link_all_deplibs, $1)=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; newsos6) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' else case $host_os in openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*) _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' ;; esac fi else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; os2*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' else _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' fi _LT_TAGVAR(archive_cmds_need_lc, $1)='no' _LT_TAGVAR(hardcode_libdir_separator, $1)=: ;; solaris*) _LT_TAGVAR(no_undefined_flag, $1)=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' fi ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4) case $host_vendor in sni) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs' _LT_TAGVAR(hardcode_direct, $1)=no ;; motorola) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; sysv4.3*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes _LT_TAGVAR(ld_shlibs, $1)=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(ld_shlibs, $1)=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym' ;; esac fi fi ]) AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld _LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl _LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl _LT_DECL([], [extract_expsyms_cmds], [2], [The commands to extract the exported symbol list from a shared archive]) # # Do we need to explicitly link libc? # case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in x|xyes) # Assume -lc should be added _LT_TAGVAR(archive_cmds_need_lc, $1)=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $_LT_TAGVAR(archive_cmds, $1) in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. AC_CACHE_CHECK([whether -lc should be explicitly linked in], [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1), [$RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if AC_TRY_EVAL(ac_compile) 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1) compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1) _LT_TAGVAR(allow_undefined_flag, $1)= if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) then lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no else lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes fi _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* ]) _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1) ;; esac fi ;; esac _LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0], [Whether or not to add -lc for building shared libraries]) _LT_TAGDECL([allow_libtool_libs_with_static_runtimes], [enable_shared_with_static_runtimes], [0], [Whether or not to disallow shared libs when runtime libs are static]) _LT_TAGDECL([], [export_dynamic_flag_spec], [1], [Compiler flag to allow reflexive dlopens]) _LT_TAGDECL([], [whole_archive_flag_spec], [1], [Compiler flag to generate shared objects directly from archives]) _LT_TAGDECL([], [compiler_needs_object], [1], [Whether the compiler copes with passing no objects directly]) _LT_TAGDECL([], [old_archive_from_new_cmds], [2], [Create an old-style archive from a shared archive]) _LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2], [Create a temporary old-style archive to link instead of a shared archive]) _LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive]) _LT_TAGDECL([], [archive_expsym_cmds], [2]) _LT_TAGDECL([], [module_cmds], [2], [Commands used to build a loadable module if different from building a shared archive.]) _LT_TAGDECL([], [module_expsym_cmds], [2]) _LT_TAGDECL([], [with_gnu_ld], [1], [Whether we are building with GNU ld or not]) _LT_TAGDECL([], [allow_undefined_flag], [1], [Flag that allows shared libraries with undefined symbols to be built]) _LT_TAGDECL([], [no_undefined_flag], [1], [Flag that enforces no undefined symbols]) _LT_TAGDECL([], [hardcode_libdir_flag_spec], [1], [Flag to hardcode $libdir into a binary during linking. This must work even if $libdir does not exist]) _LT_TAGDECL([], [hardcode_libdir_separator], [1], [Whether we need a single "-rpath" flag with a separated argument]) _LT_TAGDECL([], [hardcode_direct], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_direct_absolute], [0], [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes DIR into the resulting binary and the resulting library dependency is "absolute", i.e impossible to change by setting ${shlibpath_var} if the library is relocated]) _LT_TAGDECL([], [hardcode_minus_L], [0], [Set to "yes" if using the -LDIR flag during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_shlibpath_var], [0], [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR into the resulting binary]) _LT_TAGDECL([], [hardcode_automatic], [0], [Set to "yes" if building a shared library automatically hardcodes DIR into the library and all subsequent libraries and executables linked against it]) _LT_TAGDECL([], [inherit_rpath], [0], [Set to yes if linker adds runtime paths of dependent libraries to runtime path list]) _LT_TAGDECL([], [link_all_deplibs], [0], [Whether libtool must link a program against all its dependency libraries]) _LT_TAGDECL([], [always_export_symbols], [0], [Set to "yes" if exported symbols are required]) _LT_TAGDECL([], [export_symbols_cmds], [2], [The commands to list exported symbols]) _LT_TAGDECL([], [exclude_expsyms], [1], [Symbols that should not be listed in the preloaded symbols]) _LT_TAGDECL([], [include_expsyms], [1], [Symbols that must always be exported]) _LT_TAGDECL([], [prelink_cmds], [2], [Commands necessary for linking programs (against libraries) with templates]) _LT_TAGDECL([], [postlink_cmds], [2], [Commands necessary for finishing linking programs]) _LT_TAGDECL([], [file_list_spec], [1], [Specify filename containing input files]) dnl FIXME: Not yet implemented dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1], dnl [Compiler flag to generate thread safe objects]) ])# _LT_LINKER_SHLIBS # _LT_LANG_C_CONFIG([TAG]) # ------------------------ # Ensure that the configuration variables for a C compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_C_CONFIG], [m4_require([_LT_DECL_EGREP])dnl lt_save_CC="$CC" AC_LANG_PUSH(C) # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' _LT_TAG_COMPILER # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) LT_SYS_DLOPEN_SELF _LT_CMD_STRIPLIB # Report which library types will actually be built AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_CONFIG($1) fi AC_LANG_POP CC="$lt_save_CC" ])# _LT_LANG_C_CONFIG # _LT_LANG_CXX_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a C++ compiler are suitably # defined. These variables are subsequently used by _LT_CONFIG to write # the compiler configuration to `libtool'. m4_defun([_LT_LANG_CXX_CONFIG], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl m4_require([_LT_DECL_EGREP])dnl m4_require([_LT_PATH_MANIFEST_TOOL])dnl if test -n "$CXX" && ( test "X$CXX" != "Xno" && ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) || (test "X$CXX" != "Xg++"))) ; then AC_PROG_CXXCPP else _lt_caught_CXX_error=yes fi AC_LANG_PUSH(C++) _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(compiler_needs_object, $1)=no _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for C++ test sources. ac_ext=cpp # Object file extension for compiled C++ test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the CXX compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_caught_CXX_error" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_LD=$LD lt_save_GCC=$GCC GCC=$GXX lt_save_with_gnu_ld=$with_gnu_ld lt_save_path_LD=$lt_cv_path_LD if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx else $as_unset lt_cv_prog_gnu_ld fi if test -n "${lt_cv_path_LDCXX+set}"; then lt_cv_path_LD=$lt_cv_path_LDCXX else $as_unset lt_cv_path_LD fi test -z "${LDCXX+set}" || LD=$LDCXX CC=${CXX-"c++"} CFLAGS=$CXXFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then # We don't want -fno-exception when compiling C++ code, so set the # no_builtin_flag separately if test "$GXX" = yes; then _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' else _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)= fi if test "$GXX" = yes; then # Set up default GNU C++ configuration LT_PATH_LD # Check if GNU C++ uses GNU ld as the underlying linker, since the # archiving commands below assume that GNU ld is being used. if test "$with_gnu_ld" = yes; then _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # If archive_cmds runs LD, not CC, wlarc should be empty # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to # investigate it a little bit more. (MM) wlarc='${wl}' # ancient GNU ld didn't support --whole-archive et. al. if eval "`$CC -print-prog-name=ld` --help 2>&1" | $GREP 'no-whole-archive' > /dev/null; then _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else _LT_TAGVAR(whole_archive_flag_spec, $1)= fi else with_gnu_ld=no wlarc= # A generic and very simple default shared library creation # command for GNU C++ for the case where it uses the native # linker, instead of GNU ld. If possible, this setting should # overridden to take advantage of the native linker features on # the platform it is being used on. _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' fi # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else GXX=no with_gnu_ld=no wlarc= fi # PORTME: fill in a description of your system's C++ link characteristics AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries]) _LT_TAGVAR(ld_shlibs, $1)=yes case $host_os in aix3*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aix[[4-9]]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*) for ld_flag in $LDFLAGS; do case $ld_flag in *-brtl*) aix_use_runtimelinking=yes break ;; esac done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. _LT_TAGVAR(archive_cmds, $1)='' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(file_list_spec, $1)='${wl}-f,' if test "$GXX" = yes; then case $host_os in aix4.[[012]]|aix4.[[012]].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 _LT_TAGVAR(hardcode_direct, $1)=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking _LT_TAGVAR(hardcode_minus_L, $1)=yes _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)= fi esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to # export. _LT_TAGVAR(always_export_symbols, $1)=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. _LT_TAGVAR(allow_undefined_flag, $1)='-berok' # Determine the default libpath from the value encoded in an empty # executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib' _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs" _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. _LT_SYS_MODULE_PATH_AIX([$1]) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok' _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience' fi _LT_TAGVAR(archive_cmds_need_lc, $1)=yes # This is similar to how AIX traditionally builds its shared # libraries. _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then _LT_TAGVAR(allow_undefined_flag, $1)=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; chorus*) case $cc_basename in *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; cygwin* | mingw* | pw32* | cegcc*) case $GXX,$cc_basename in ,cl* | no,cl*) # Native MSVC # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' ' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=yes _LT_TAGVAR(file_list_spec, $1)='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true' _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes # Don't use ranlib _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib' _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ func_to_tool_file "$lt_outputfile"~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # g++ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless, # as there is no search path for DLLs. _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols' _LT_TAGVAR(allow_undefined_flag, $1)=unsupported _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; darwin* | rhapsody*) _LT_DARWIN_LINKER_FEATURES($1) ;; dgux*) case $cc_basename in ec++*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; ghcx*) # Green Hills C++ Compiler # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; freebsd2.*) # C++ shared libraries reported to be fairly broken before # switch to ELF _LT_TAGVAR(ld_shlibs, $1)=no ;; freebsd-elf*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; freebsd* | dragonfly*) # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF # conventions _LT_TAGVAR(ld_shlibs, $1)=yes ;; gnu*) ;; haiku*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(link_all_deplibs, $1)=yes ;; hpux9*) _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; hpux10*|hpux11*) if test $with_gnu_ld = no; then _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: case $host_cpu in hppa*64*|ia64*) ;; *) _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' ;; esac fi case $host_cpu in hppa*64*|ia64*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no ;; *) _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH, # but as the default # location of the library. ;; esac case $cc_basename in CC*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; aCC*) case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes; then if test $with_gnu_ld = no; then case $host_cpu in hppa*64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; ia64*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' ;; esac fi else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; interix[[3-9]]*) _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; irix5* | irix6*) case $cc_basename in CC*) # SGI C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' # Archives containing C++ object files must be created using # "CC -ar", where "CC" is the IRIX C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs' ;; *) if test "$GXX" = yes; then if test "$with_gnu_ld" = no; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib' fi fi _LT_TAGVAR(link_all_deplibs, $1)=yes ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: _LT_TAGVAR(inherit_rpath, $1)=yes ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' # Archives containing C++ object files must be created using # "CC -Bstatic", where "CC" is the KAI C++ compiler. _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; icpc* | ecpc* ) # Intel C++ with_gnu_ld=yes # version 8.0 and above of icpc choke on multiply defined symbols # if we add $predep_objects and $postdep_objects, however 7.1 and # earlier do not add the objects themselves. case `$CC -V 2>&1` in *"Version 7."*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; *) # Version 8.0 or newer tmp_idyn= case $host_cpu in ia64*) tmp_idyn=' -i_dynamic';; esac _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' ;; esac _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive' ;; pgCC* | pgcpp*) # Portland Group C++ compiler case `$CC -V` in *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*) _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"' _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~ $RANLIB $oldlib' _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~ rm -rf $tpldir~ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; *) # Version 6 and above use weak symbols _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' ;; cxx*) # Compaq C++ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols' runpath_var=LD_RUN_PATH _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed' ;; xl* | mpixl* | bgxl*) # IBM XL 8.0 on PPC, with GNU ld _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic' _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' _LT_TAGVAR(compiler_needs_object, $1)=yes # Not sure whether something based on # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 # would be better. output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; esac ;; esac ;; lynxos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; m88k*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; mvs*) case $cc_basename in cxx*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; netbsd*) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags' wlarc= _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no fi # Workaround some broken pre-1.5 toolchains output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"' ;; *nto* | *qnx*) _LT_TAGVAR(ld_shlibs, $1)=yes ;; openbsd2*) # C++ shared libraries are fairly broken _LT_TAGVAR(ld_shlibs, $1)=no ;; openbsd*) if test -f /usr/libexec/ld.so; then _LT_TAGVAR(hardcode_direct, $1)=yes _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=yes _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib' _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E' _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' fi output_verbose_link_cmd=func_echo_all else _LT_TAGVAR(ld_shlibs, $1)=no fi ;; osf3* | osf4* | osf5*) case $cc_basename in KCC*) # Kuck and Associates, Inc. (KAI) C++ Compiler # KCC will only create a shared library if the output file # ends with ".so" (or ".sl" for HP-UX), so rename the library # to its proper name (with version) after linking. _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Archives containing C++ object files must be created using # the KAI C++ compiler. case $host in osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;; *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;; esac ;; RCC*) # Rational C++ 2.4.1 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; cxx*) case $host in osf3*) _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' ;; *) _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*' _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~ echo "-hidden">> $lib.exp~ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~ $RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir' ;; esac _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. # # There doesn't appear to be a way to prevent this compiler from # explicitly linking system object files so we need to strip them # from the output so that they don't get included in the library # dependencies. output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"' ;; *) if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*' case $host in osf3*) _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' ;; esac _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=: # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no fi ;; esac ;; psos*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; sunos4*) case $cc_basename in CC*) # Sun C++ 4.x # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; lcc*) # Lucid # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # Sun C++ 4.2, 5.x and Centerline C++ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs' _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir' _LT_TAGVAR(hardcode_shlibpath_var, $1)=no case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. # Supported since Solaris 2.6 (maybe 2.5.1?) _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract' ;; esac _LT_TAGVAR(link_all_deplibs, $1)=yes output_verbose_link_cmd='func_echo_all' # Archives containing C++ object files must be created using # "CC -xar", where "CC" is the Sun C++ compiler. This is # necessary to make sure instantiated templates are included # in the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs' ;; gcx*) # Green Hills C++ Compiler _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' # The C++ compiler must be used to create the archive. _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs' ;; *) # GNU C++ compiler with Solaris linker if test "$GXX" = yes && test "$with_gnu_ld" = no; then _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs' if $CC --version | $GREP -v '^2\.7' > /dev/null; then _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' else # g++ 2.7 appears to require `-G' NOT `-shared' on this # platform. _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib' _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp' # Commands to make compiler produce verbose output that lists # what "hidden" libraries, object files and flags are used when # linking a shared library. output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"' fi _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir' case $host_os in solaris2.[[0-5]] | solaris2.[[0-5]].*) ;; *) _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' ;; esac fi ;; esac ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*) _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text' _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs' _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(hardcode_shlibpath_var, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir' _LT_TAGVAR(hardcode_libdir_separator, $1)=':' _LT_TAGVAR(link_all_deplibs, $1)=yes _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport' runpath_var='LD_RUN_PATH' case $cc_basename in CC*) _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~ '"$_LT_TAGVAR(old_archive_cmds, $1)" _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~ '"$_LT_TAGVAR(reload_cmds, $1)" ;; *) _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' ;; esac ;; tandem*) case $cc_basename in NCC*) # NonStop-UX NCC 3.20 # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac ;; vxworks*) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; *) # FIXME: insert proper C++ library support _LT_TAGVAR(ld_shlibs, $1)=no ;; esac AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)]) test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no _LT_TAGVAR(GCC, $1)="$GXX" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS LDCXX=$LD LD=$lt_save_LD GCC=$lt_save_GCC with_gnu_ld=$lt_save_with_gnu_ld lt_cv_path_LDCXX=$lt_cv_path_LD lt_cv_path_LD=$lt_save_path_LD lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld fi # test "$_lt_caught_CXX_error" != yes AC_LANG_POP ])# _LT_LANG_CXX_CONFIG # _LT_FUNC_STRIPNAME_CNF # ---------------------- # func_stripname_cnf prefix suffix name # strip PREFIX and SUFFIX off of NAME. # PREFIX and SUFFIX must not contain globbing or regex special # characters, hashes, percent signs, but SUFFIX may contain a leading # dot (in which case that matches only a dot). # # This function is identical to the (non-XSI) version of func_stripname, # except this one can be used by m4 code that may be executed by configure, # rather than the libtool script. m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl AC_REQUIRE([_LT_DECL_SED]) AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH]) func_stripname_cnf () { case ${2} in .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;; *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;; esac } # func_stripname_cnf ])# _LT_FUNC_STRIPNAME_CNF # _LT_SYS_HIDDEN_LIBDEPS([TAGNAME]) # --------------------------------- # Figure out "hidden" library dependencies from verbose # compiler output when linking a shared library. # Parse the compiler output and extract the necessary # objects, libraries and library flags. m4_defun([_LT_SYS_HIDDEN_LIBDEPS], [m4_require([_LT_FILEUTILS_DEFAULTS])dnl AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl # Dependencies to place before and after the object being linked: _LT_TAGVAR(predep_objects, $1)= _LT_TAGVAR(postdep_objects, $1)= _LT_TAGVAR(predeps, $1)= _LT_TAGVAR(postdeps, $1)= _LT_TAGVAR(compiler_lib_search_path, $1)= dnl we can't use the lt_simple_compile_test_code here, dnl because it contains code intended for an executable, dnl not a library. It's possible we should let each dnl tag define a new lt_????_link_test_code variable, dnl but it's only used here... m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF int a; void foo (void) { a = 0; } _LT_EOF ], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF class Foo { public: Foo (void) { a = 0; } private: int a; }; _LT_EOF ], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer*4 a a=0 return end _LT_EOF ], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF subroutine foo implicit none integer a a=0 return end _LT_EOF ], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF public class foo { private int a; public void bar (void) { a = 0; } }; _LT_EOF ], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF package foo func foo() { } _LT_EOF ]) _lt_libdeps_save_CFLAGS=$CFLAGS case "$CC $CFLAGS " in #( *\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;; *\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;; *\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;; esac dnl Parse the compiler output and extract the necessary dnl objects, libraries and library flags. if AC_TRY_EVAL(ac_compile); then # Parse the compiler output and extract the necessary # objects, libraries and library flags. # Sentinel used to keep track of whether or not we are before # the conftest object file. pre_test_object_deps_done=no for p in `eval "$output_verbose_link_cmd"`; do case ${prev}${p} in -L* | -R* | -l*) # Some compilers place space between "-{L,R}" and the path. # Remove the space. if test $p = "-L" || test $p = "-R"; then prev=$p continue fi # Expand the sysroot to ease extracting the directories later. if test -z "$prev"; then case $p in -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;; -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;; -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;; esac fi case $p in =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;; esac if test "$pre_test_object_deps_done" = no; then case ${prev} in -L | -R) # Internal compiler library paths should come after those # provided the user. The postdeps already come after the # user supplied libs so there is no need to process them. if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}" else _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}" fi ;; # The "-l" case would never come before the object being # linked, so don't bother handling this case. esac else if test -z "$_LT_TAGVAR(postdeps, $1)"; then _LT_TAGVAR(postdeps, $1)="${prev}${p}" else _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}" fi fi prev= ;; *.lto.$objext) ;; # Ignore GCC LTO objects *.$objext) # This assumes that the test object file only shows up # once in the compiler output. if test "$p" = "conftest.$objext"; then pre_test_object_deps_done=yes continue fi if test "$pre_test_object_deps_done" = no; then if test -z "$_LT_TAGVAR(predep_objects, $1)"; then _LT_TAGVAR(predep_objects, $1)="$p" else _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p" fi else if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then _LT_TAGVAR(postdep_objects, $1)="$p" else _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p" fi fi ;; *) ;; # Ignore the rest. esac done # Clean up. rm -f a.out a.exe else echo "libtool.m4: error: problem compiling $1 test program" fi $RM -f confest.$objext CFLAGS=$_lt_libdeps_save_CFLAGS # PORTME: override above test on systems where it is broken m4_if([$1], [CXX], [case $host_os in interix[[3-9]]*) # Interix 3.5 installs completely hosed .la files for C++, so rather than # hack all around it, let's just trust "g++" to DTRT. _LT_TAGVAR(predep_objects,$1)= _LT_TAGVAR(postdep_objects,$1)= _LT_TAGVAR(postdeps,$1)= ;; linux*) case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C++ 5.9 # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; solaris*) case $cc_basename in CC* | sunCC*) # The more standards-conforming stlport4 library is # incompatible with the Cstd library. Avoid specifying # it if it's in CXXFLAGS. Ignore libCrun as # -library=stlport4 depends on it. case " $CXX $CXXFLAGS " in *" -library=stlport4 "*) solaris_use_stlport4=yes ;; esac # Adding this requires a known-good setup of shared libraries for # Sun compiler versions before 5.6, else PIC objects from an old # archive will be linked into the output, leading to subtle bugs. if test "$solaris_use_stlport4" != yes; then _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun' fi ;; esac ;; esac ]) case " $_LT_TAGVAR(postdeps, $1) " in *" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;; esac _LT_TAGVAR(compiler_lib_search_dirs, $1)= if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'` fi _LT_TAGDECL([], [compiler_lib_search_dirs], [1], [The directories searched by this compiler when creating a shared library]) _LT_TAGDECL([], [predep_objects], [1], [Dependencies to place before and after the objects being linked to create a shared library]) _LT_TAGDECL([], [postdep_objects], [1]) _LT_TAGDECL([], [predeps], [1]) _LT_TAGDECL([], [postdeps], [1]) _LT_TAGDECL([], [compiler_lib_search_path], [1], [The library search path used internally by the compiler when linking a shared library]) ])# _LT_SYS_HIDDEN_LIBDEPS # _LT_LANG_F77_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for a Fortran 77 compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_F77_CONFIG], [AC_LANG_PUSH(Fortran 77) if test -z "$F77" || test "X$F77" = "Xno"; then _lt_disable_F77=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for f77 test sources. ac_ext=f # Object file extension for compiled f77 test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the F77 compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_F77" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${F77-"f77"} CFLAGS=$FFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) GCC=$G77 if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$G77" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC="$lt_save_CC" CFLAGS="$lt_save_CFLAGS" fi # test "$_lt_disable_F77" != yes AC_LANG_POP ])# _LT_LANG_F77_CONFIG # _LT_LANG_FC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for a Fortran compiler are # suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_FC_CONFIG], [AC_LANG_PUSH(Fortran) if test -z "$FC" || test "X$FC" = "Xno"; then _lt_disable_FC=yes fi _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(allow_undefined_flag, $1)= _LT_TAGVAR(always_export_symbols, $1)=no _LT_TAGVAR(archive_expsym_cmds, $1)= _LT_TAGVAR(export_dynamic_flag_spec, $1)= _LT_TAGVAR(hardcode_direct, $1)=no _LT_TAGVAR(hardcode_direct_absolute, $1)=no _LT_TAGVAR(hardcode_libdir_flag_spec, $1)= _LT_TAGVAR(hardcode_libdir_separator, $1)= _LT_TAGVAR(hardcode_minus_L, $1)=no _LT_TAGVAR(hardcode_automatic, $1)=no _LT_TAGVAR(inherit_rpath, $1)=no _LT_TAGVAR(module_cmds, $1)= _LT_TAGVAR(module_expsym_cmds, $1)= _LT_TAGVAR(link_all_deplibs, $1)=unknown _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds _LT_TAGVAR(no_undefined_flag, $1)= _LT_TAGVAR(whole_archive_flag_spec, $1)= _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no # Source file extension for fc test sources. ac_ext=${ac_fc_srcext-f} # Object file extension for compiled fc test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # No sense in running all these tests if we already determined that # the FC compiler isn't working. Some variables (like enable_shared) # are currently assumed to apply to all compilers on this platform, # and will be corrupted by setting them based on a non-working compiler. if test "$_lt_disable_FC" != yes; then # Code to be used in simple compile tests lt_simple_compile_test_code="\ subroutine t return end " # Code to be used in simple link tests lt_simple_link_test_code="\ program t end " # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_GCC=$GCC lt_save_CFLAGS=$CFLAGS CC=${FC-"f95"} CFLAGS=$FCFLAGS compiler=$CC GCC=$ac_cv_fc_compiler_gnu _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) if test -n "$compiler"; then AC_MSG_CHECKING([if libtool supports shared libraries]) AC_MSG_RESULT([$can_build_shared]) AC_MSG_CHECKING([whether to build shared libraries]) test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[[4-9]]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac AC_MSG_RESULT([$enable_shared]) AC_MSG_CHECKING([whether to build static libraries]) # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes AC_MSG_RESULT([$enable_static]) _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu" _LT_TAGVAR(LD, $1)="$LD" ## CAVEAT EMPTOR: ## There is no encapsulation within the following macros, do not change ## the running order or otherwise move them around unless you know exactly ## what you are doing... _LT_SYS_HIDDEN_LIBDEPS($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_SYS_DYNAMIC_LINKER($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi # test -n "$compiler" GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS fi # test "$_lt_disable_FC" != yes AC_LANG_POP ])# _LT_LANG_FC_CONFIG # _LT_LANG_GCJ_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Java Compiler compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GCJ_CONFIG], [AC_REQUIRE([LT_PROG_GCJ])dnl AC_LANG_SAVE # Source file extension for Java test sources. ac_ext=java # Object file extension for compiled Java test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="class foo {}" # Code to be used in simple link tests lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GCJ-"gcj"} CFLAGS=$GCJFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # GCJ did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GCJ_CONFIG # _LT_LANG_GO_CONFIG([TAG]) # -------------------------- # Ensure that the configuration variables for the GNU Go compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_GO_CONFIG], [AC_REQUIRE([LT_PROG_GO])dnl AC_LANG_SAVE # Source file extension for Go test sources. ac_ext=go # Object file extension for compiled Go test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="package main; func main() { }" # Code to be used in simple link tests lt_simple_link_test_code='package main; func main() { }' # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC=$CC lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC=yes CC=${GOC-"gccgo"} CFLAGS=$GOFLAGS compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_TAGVAR(LD, $1)="$LD" _LT_CC_BASENAME([$compiler]) # Go did not exist at the time GCC didn't implicitly link libc in. _LT_TAGVAR(archive_cmds_need_lc, $1)=no _LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds _LT_TAGVAR(reload_flag, $1)=$reload_flag _LT_TAGVAR(reload_cmds, $1)=$reload_cmds if test -n "$compiler"; then _LT_COMPILER_NO_RTTI($1) _LT_COMPILER_PIC($1) _LT_COMPILER_C_O($1) _LT_COMPILER_FILE_LOCKS($1) _LT_LINKER_SHLIBS($1) _LT_LINKER_HARDCODE_LIBPATH($1) _LT_CONFIG($1) fi AC_LANG_RESTORE GCC=$lt_save_GCC CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_GO_CONFIG # _LT_LANG_RC_CONFIG([TAG]) # ------------------------- # Ensure that the configuration variables for the Windows resource compiler # are suitably defined. These variables are subsequently used by _LT_CONFIG # to write the compiler configuration to `libtool'. m4_defun([_LT_LANG_RC_CONFIG], [AC_REQUIRE([LT_PROG_RC])dnl AC_LANG_SAVE # Source file extension for RC test sources. ac_ext=rc # Object file extension for compiled RC test sources. objext=o _LT_TAGVAR(objext, $1)=$objext # Code to be used in simple compile tests lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }' # Code to be used in simple link tests lt_simple_link_test_code="$lt_simple_compile_test_code" # ltmain only uses $CC for tagged configurations so make sure $CC is set. _LT_TAG_COMPILER # save warnings/boilerplate of simple test code _LT_COMPILER_BOILERPLATE _LT_LINKER_BOILERPLATE # Allow CC to be a program name with arguments. lt_save_CC="$CC" lt_save_CFLAGS=$CFLAGS lt_save_GCC=$GCC GCC= CC=${RC-"windres"} CFLAGS= compiler=$CC _LT_TAGVAR(compiler, $1)=$CC _LT_CC_BASENAME([$compiler]) _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes if test -n "$compiler"; then : _LT_CONFIG($1) fi GCC=$lt_save_GCC AC_LANG_RESTORE CC=$lt_save_CC CFLAGS=$lt_save_CFLAGS ])# _LT_LANG_RC_CONFIG # LT_PROG_GCJ # ----------- AC_DEFUN([LT_PROG_GCJ], [m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ], [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ], [AC_CHECK_TOOL(GCJ, gcj,) test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2" AC_SUBST(GCJFLAGS)])])[]dnl ]) # Old name: AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_GCJ], []) # LT_PROG_GO # ---------- AC_DEFUN([LT_PROG_GO], [AC_CHECK_TOOL(GOC, gccgo,) ]) # LT_PROG_RC # ---------- AC_DEFUN([LT_PROG_RC], [AC_CHECK_TOOL(RC, windres,) ]) # Old name: AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_RC], []) # _LT_DECL_EGREP # -------------- # If we don't have a new enough Autoconf to choose the best grep # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_EGREP], [AC_REQUIRE([AC_PROG_EGREP])dnl AC_REQUIRE([AC_PROG_FGREP])dnl test -z "$GREP" && GREP=grep _LT_DECL([], [GREP], [1], [A grep program that handles long lines]) _LT_DECL([], [EGREP], [1], [An ERE matcher]) _LT_DECL([], [FGREP], [1], [A literal string matcher]) dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too AC_SUBST([GREP]) ]) # _LT_DECL_OBJDUMP # -------------- # If we don't have a new enough Autoconf to choose the best objdump # available, choose the one first in the user's PATH. m4_defun([_LT_DECL_OBJDUMP], [AC_CHECK_TOOL(OBJDUMP, objdump, false) test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [An object symbol dumper]) AC_SUBST([OBJDUMP]) ]) # _LT_DECL_DLLTOOL # ---------------- # Ensure DLLTOOL variable is set. m4_defun([_LT_DECL_DLLTOOL], [AC_CHECK_TOOL(DLLTOOL, dlltool, false) test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program]) AC_SUBST([DLLTOOL]) ]) # _LT_DECL_SED # ------------ # Check for a fully-functional sed program, that truncates # as few characters as possible. Prefer GNU sed if found. m4_defun([_LT_DECL_SED], [AC_PROG_SED test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" _LT_DECL([], [SED], [1], [A sed program that does not truncate output]) _LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"], [Sed that helps us avoid accidentally triggering echo(1) options like -n]) ])# _LT_DECL_SED m4_ifndef([AC_PROG_SED], [ # NOTE: This macro has been submitted for inclusion into # # GNU Autoconf as AC_PROG_SED. When it is available in # # a released version of Autoconf we should remove this # # macro and use it instead. # m4_defun([AC_PROG_SED], [AC_MSG_CHECKING([for a sed that does not truncate output]) AC_CACHE_VAL(lt_cv_path_SED, [# Loop through the user's path and test for sed and gsed. # Then use that list of sed's as ones to test for truncation. as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for lt_ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext" fi done done done IFS=$as_save_IFS lt_ac_max=0 lt_ac_count=0 # Add /usr/xpg4/bin/sed as it is typically found on Solaris # along with /bin/sed that truncates output. for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do test ! -f $lt_ac_sed && continue cat /dev/null > conftest.in lt_ac_count=0 echo $ECHO_N "0123456789$ECHO_C" >conftest.in # Check for GNU sed and select it if it is found. if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then lt_cv_path_SED=$lt_ac_sed break fi while true; do cat conftest.in conftest.in >conftest.tmp mv conftest.tmp conftest.in cp conftest.in conftest.nl echo >>conftest.nl $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break cmp -s conftest.out conftest.nl || break # 10000 chars as input seems more than enough test $lt_ac_count -gt 10 && break lt_ac_count=`expr $lt_ac_count + 1` if test $lt_ac_count -gt $lt_ac_max; then lt_ac_max=$lt_ac_count lt_cv_path_SED=$lt_ac_sed fi done done ]) SED=$lt_cv_path_SED AC_SUBST([SED]) AC_MSG_RESULT([$SED]) ])#AC_PROG_SED ])#m4_ifndef # Old name: AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([LT_AC_PROG_SED], []) # _LT_CHECK_SHELL_FEATURES # ------------------------ # Find out whether the shell is Bourne or XSI compatible, # or has some other useful features. m4_defun([_LT_CHECK_SHELL_FEATURES], [AC_MSG_CHECKING([whether the shell understands some XSI constructs]) # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes AC_MSG_RESULT([$xsi_shell]) _LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell']) AC_MSG_CHECKING([whether the shell understands "+="]) lt_shell_append=no ( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes AC_MSG_RESULT([$lt_shell_append]) _LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append']) if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi _LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac _LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl _LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl ])# _LT_CHECK_SHELL_FEATURES # _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY) # ------------------------------------------------------ # In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and # '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY. m4_defun([_LT_PROG_FUNCTION_REPLACE], [dnl { sed -e '/^$1 ()$/,/^} # $1 /c\ $1 ()\ {\ m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1]) } # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: ]) # _LT_PROG_REPLACE_SHELLFNS # ------------------------- # Replace existing portable implementations of several shell functions with # equivalent extended shell implementations where those features are available.. m4_defun([_LT_PROG_REPLACE_SHELLFNS], [if test x"$xsi_shell" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl case ${1} in */*) func_dirname_result="${1%/*}${2}" ;; * ) func_dirname_result="${3}" ;; esac func_basename_result="${1##*/}"]) _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are # positional parameters, so assign one to ordinary parameter first. func_stripname_result=${3} func_stripname_result=${func_stripname_result#"${1}"} func_stripname_result=${func_stripname_result%"${2}"}]) _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl func_split_long_opt_name=${1%%=*} func_split_long_opt_arg=${1#*=}]) _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl func_split_short_opt_arg=${1#??} func_split_short_opt_name=${1%"$func_split_short_opt_arg"}]) _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl case ${1} in *.lo) func_lo2o_result=${1%.lo}.${objext} ;; *) func_lo2o_result=${1} ;; esac]) _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo]) _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))]) _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}]) fi if test x"$lt_shell_append" = xyes; then _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"]) _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl func_quote_for_eval "${2}" dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"]) # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then AC_MSG_WARN([Unable to substitute extended shell functions in $ofile]) fi ]) # _LT_PATH_CONVERSION_FUNCTIONS # ----------------------------- # Determine which file name conversion functions should be used by # func_to_host_file (and, implicitly, by func_to_host_path). These are needed # for certain cross-compile configurations and native mingw. m4_defun([_LT_PATH_CONVERSION_FUNCTIONS], [AC_REQUIRE([AC_CANONICAL_HOST])dnl AC_REQUIRE([AC_CANONICAL_BUILD])dnl AC_MSG_CHECKING([how to convert $build file names to $host format]) AC_CACHE_VAL(lt_cv_to_host_file_cmd, [case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac ]) to_host_file_cmd=$lt_cv_to_host_file_cmd AC_MSG_RESULT([$lt_cv_to_host_file_cmd]) _LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd], [0], [convert $build file names to $host format])dnl AC_MSG_CHECKING([how to convert $build file names to toolchain format]) AC_CACHE_VAL(lt_cv_to_tool_file_cmd, [#assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac ]) to_tool_file_cmd=$lt_cv_to_tool_file_cmd AC_MSG_RESULT([$lt_cv_to_tool_file_cmd]) _LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd], [0], [convert $build files to toolchain format])dnl ])# _LT_PATH_CONVERSION_FUNCTIONS # Helper functions for option handling. -*- Autoconf -*- # # Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation, # Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 7 ltoptions.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])]) # _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME) # ------------------------------------------ m4_define([_LT_MANGLE_OPTION], [[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])]) # _LT_SET_OPTION(MACRO-NAME, OPTION-NAME) # --------------------------------------- # Set option OPTION-NAME for macro MACRO-NAME, and if there is a # matching handler defined, dispatch to it. Other OPTION-NAMEs are # saved as a flag. m4_define([_LT_SET_OPTION], [m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]), _LT_MANGLE_DEFUN([$1], [$2]), [m4_warning([Unknown $1 option `$2'])])[]dnl ]) # _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET]) # ------------------------------------------------------------ # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. m4_define([_LT_IF_OPTION], [m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])]) # _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET) # ------------------------------------------------------- # Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME # are set. m4_define([_LT_UNLESS_OPTIONS], [m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option), [m4_define([$0_found])])])[]dnl m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3 ])[]dnl ]) # _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST) # ---------------------------------------- # OPTION-LIST is a space-separated list of Libtool options associated # with MACRO-NAME. If any OPTION has a matching handler declared with # LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about # the unknown option and exit. m4_defun([_LT_SET_OPTIONS], [# Set options m4_foreach([_LT_Option], m4_split(m4_normalize([$2])), [_LT_SET_OPTION([$1], _LT_Option)]) m4_if([$1],[LT_INIT],[ dnl dnl Simply set some default values (i.e off) if boolean options were not dnl specified: _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no ]) _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no ]) dnl dnl If no reference was made to various pairs of opposing options, then dnl we run the default mode handler for the pair. For example, if neither dnl `shared' nor `disable-shared' was passed, we enable building of shared dnl archives by default: _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED]) _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC]) _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC]) _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install], [_LT_ENABLE_FAST_INSTALL]) ]) ])# _LT_SET_OPTIONS # _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME) # ----------------------------------------- m4_define([_LT_MANGLE_DEFUN], [[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])]) # LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE) # ----------------------------------------------- m4_define([LT_OPTION_DEFINE], [m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl ])# LT_OPTION_DEFINE # dlopen # ------ LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes ]) AU_DEFUN([AC_LIBTOOL_DLOPEN], [_LT_SET_OPTION([LT_INIT], [dlopen]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `dlopen' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], []) # win32-dll # --------- # Declare package support for building win32 dll's. LT_OPTION_DEFINE([LT_INIT], [win32-dll], [enable_win32_dll=yes case $host in *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*) AC_CHECK_TOOL(AS, as, false) AC_CHECK_TOOL(DLLTOOL, dlltool, false) AC_CHECK_TOOL(OBJDUMP, objdump, false) ;; esac test -z "$AS" && AS=as _LT_DECL([], [AS], [1], [Assembler program])dnl test -z "$DLLTOOL" && DLLTOOL=dlltool _LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl test -z "$OBJDUMP" && OBJDUMP=objdump _LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl ])# win32-dll AU_DEFUN([AC_LIBTOOL_WIN32_DLL], [AC_REQUIRE([AC_CANONICAL_HOST])dnl _LT_SET_OPTION([LT_INIT], [win32-dll]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `win32-dll' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], []) # _LT_ENABLE_SHARED([DEFAULT]) # ---------------------------- # implement the --enable-shared flag, and supports the `shared' and # `disable-shared' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_SHARED], [m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([shared], [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@], [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_shared=]_LT_ENABLE_SHARED_DEFAULT) _LT_DECL([build_libtool_libs], [enable_shared], [0], [Whether or not to build shared libraries]) ])# _LT_ENABLE_SHARED LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])]) # Old names: AC_DEFUN([AC_ENABLE_SHARED], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared]) ]) AC_DEFUN([AC_DISABLE_SHARED], [_LT_SET_OPTION([LT_INIT], [disable-shared]) ]) AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)]) AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_SHARED], []) dnl AC_DEFUN([AM_DISABLE_SHARED], []) # _LT_ENABLE_STATIC([DEFAULT]) # ---------------------------- # implement the --enable-static flag, and support the `static' and # `disable-static' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_STATIC], [m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([static], [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@], [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_static=]_LT_ENABLE_STATIC_DEFAULT) _LT_DECL([build_old_libs], [enable_static], [0], [Whether or not to build static libraries]) ])# _LT_ENABLE_STATIC LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])]) # Old names: AC_DEFUN([AC_ENABLE_STATIC], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static]) ]) AC_DEFUN([AC_DISABLE_STATIC], [_LT_SET_OPTION([LT_INIT], [disable-static]) ]) AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)]) AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AM_ENABLE_STATIC], []) dnl AC_DEFUN([AM_DISABLE_STATIC], []) # _LT_ENABLE_FAST_INSTALL([DEFAULT]) # ---------------------------------- # implement the --enable-fast-install flag, and support the `fast-install' # and `disable-fast-install' LT_INIT options. # DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'. m4_define([_LT_ENABLE_FAST_INSTALL], [m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl AC_ARG_ENABLE([fast-install], [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@], [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])], [p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac], [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT) _LT_DECL([fast_install], [enable_fast_install], [0], [Whether or not to optimize for fast installation])dnl ])# _LT_ENABLE_FAST_INSTALL LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])]) LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])]) # Old names: AU_DEFUN([AC_ENABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `fast-install' option into LT_INIT's first parameter.]) ]) AU_DEFUN([AC_DISABLE_FAST_INSTALL], [_LT_SET_OPTION([LT_INIT], [disable-fast-install]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `disable-fast-install' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], []) dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], []) # _LT_WITH_PIC([MODE]) # -------------------- # implement the --with-pic flag, and support the `pic-only' and `no-pic' # LT_INIT options. # MODE is either `yes' or `no'. If omitted, it defaults to `both'. m4_define([_LT_WITH_PIC], [AC_ARG_WITH([pic], [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@], [try to use only PIC/non-PIC objects @<:@default=use both@:>@])], [lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac], [pic_mode=default]) test -z "$pic_mode" && pic_mode=m4_default([$1], [default]) _LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl ])# _LT_WITH_PIC LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])]) LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])]) # Old name: AU_DEFUN([AC_LIBTOOL_PICMODE], [_LT_SET_OPTION([LT_INIT], [pic-only]) AC_DIAGNOSE([obsolete], [$0: Remove this warning and the call to _LT_SET_OPTION when you put the `pic-only' option into LT_INIT's first parameter.]) ]) dnl aclocal-1.4 backwards compatibility: dnl AC_DEFUN([AC_LIBTOOL_PICMODE], []) m4_define([_LTDL_MODE], []) LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive], [m4_define([_LTDL_MODE], [nonrecursive])]) LT_OPTION_DEFINE([LTDL_INIT], [recursive], [m4_define([_LTDL_MODE], [recursive])]) LT_OPTION_DEFINE([LTDL_INIT], [subproject], [m4_define([_LTDL_MODE], [subproject])]) m4_define([_LTDL_TYPE], []) LT_OPTION_DEFINE([LTDL_INIT], [installable], [m4_define([_LTDL_TYPE], [installable])]) LT_OPTION_DEFINE([LTDL_INIT], [convenience], [m4_define([_LTDL_TYPE], [convenience])]) # ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc. # Written by Gary V. Vaughan, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 6 ltsugar.m4 # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])]) # lt_join(SEP, ARG1, [ARG2...]) # ----------------------------- # Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their # associated separator. # Needed until we can rely on m4_join from Autoconf 2.62, since all earlier # versions in m4sugar had bugs. m4_define([lt_join], [m4_if([$#], [1], [], [$#], [2], [[$2]], [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])]) m4_define([_lt_join], [m4_if([$#$2], [2], [], [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])]) # lt_car(LIST) # lt_cdr(LIST) # ------------ # Manipulate m4 lists. # These macros are necessary as long as will still need to support # Autoconf-2.59 which quotes differently. m4_define([lt_car], [[$1]]) m4_define([lt_cdr], [m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])], [$#], 1, [], [m4_dquote(m4_shift($@))])]) m4_define([lt_unquote], $1) # lt_append(MACRO-NAME, STRING, [SEPARATOR]) # ------------------------------------------ # Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'. # Note that neither SEPARATOR nor STRING are expanded; they are appended # to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked). # No SEPARATOR is output if MACRO-NAME was previously undefined (different # than defined and empty). # # This macro is needed until we can rely on Autoconf 2.62, since earlier # versions of m4sugar mistakenly expanded SEPARATOR but not STRING. m4_define([lt_append], [m4_define([$1], m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])]) # lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...]) # ---------------------------------------------------------- # Produce a SEP delimited list of all paired combinations of elements of # PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list # has the form PREFIXmINFIXSUFFIXn. # Needed until we can rely on m4_combine added in Autoconf 2.62. m4_define([lt_combine], [m4_if(m4_eval([$# > 3]), [1], [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl [[m4_foreach([_Lt_prefix], [$2], [m4_foreach([_Lt_suffix], ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[, [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])]) # lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ]) # ----------------------------------------------------------------------- # Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited # by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ. m4_define([lt_if_append_uniq], [m4_ifdef([$1], [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1], [lt_append([$1], [$2], [$3])$4], [$5])], [lt_append([$1], [$2], [$3])$4])]) # lt_dict_add(DICT, KEY, VALUE) # ----------------------------- m4_define([lt_dict_add], [m4_define([$1($2)], [$3])]) # lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE) # -------------------------------------------- m4_define([lt_dict_add_subkey], [m4_define([$1($2:$3)], [$4])]) # lt_dict_fetch(DICT, KEY, [SUBKEY]) # ---------------------------------- m4_define([lt_dict_fetch], [m4_ifval([$3], m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]), m4_ifdef([$1($2)], [m4_defn([$1($2)])]))]) # lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE]) # ----------------------------------------------------------------- m4_define([lt_if_dict_fetch], [m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4], [$5], [$6])]) # lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...]) # -------------------------------------------------------------- m4_define([lt_dict_filter], [m4_if([$5], [], [], [lt_join(m4_quote(m4_default([$4], [[, ]])), lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]), [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl ]) # ltversion.m4 -- version numbers -*- Autoconf -*- # # Copyright (C) 2004 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004 # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # @configure_input@ # serial 3337 ltversion.m4 # This file is part of GNU Libtool m4_define([LT_PACKAGE_VERSION], [2.4.2]) m4_define([LT_PACKAGE_REVISION], [1.3337]) AC_DEFUN([LTVERSION_VERSION], [macro_version='2.4.2' macro_revision='1.3337' _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?]) _LT_DECL(, macro_revision, 0) ]) # lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*- # # Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc. # Written by Scott James Remnant, 2004. # # This file is free software; the Free Software Foundation gives # unlimited permission to copy and/or distribute it, with or without # modifications, as long as this notice is preserved. # serial 5 lt~obsolete.m4 # These exist entirely to fool aclocal when bootstrapping libtool. # # In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN) # which have later been changed to m4_define as they aren't part of the # exported API, or moved to Autoconf or Automake where they belong. # # The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN # in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us # using a macro with the same name in our local m4/libtool.m4 it'll # pull the old libtool.m4 in (it doesn't see our shiny new m4_define # and doesn't know about Autoconf macros at all.) # # So we provide this file, which has a silly filename so it's always # included after everything else. This provides aclocal with the # AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything # because those macros already exist, or will be overwritten later. # We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6. # # Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here. # Yes, that means every name once taken will need to remain here until # we give up compatibility with versions before 1.7, at which point # we need to keep only those names which we still refer to. # This is to help aclocal find these macros, as it can't see m4_define. AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])]) m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])]) m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])]) m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])]) m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])]) m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])]) m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])]) m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])]) m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])]) m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])]) m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])]) m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])]) m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])]) m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])]) m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])]) m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])]) m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])]) m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])]) m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])]) m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])]) m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])]) m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])]) m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])]) m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])]) m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])]) m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])]) m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])]) m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])]) m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])]) m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])]) m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])]) m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])]) m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])]) m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])]) m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])]) m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])]) m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])]) m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])]) m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])]) m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])]) m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])]) m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])]) m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])]) m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])]) m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])]) m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])]) m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])]) m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])]) m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])]) m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])]) m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])]) m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])]) m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])]) m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])]) m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])]) m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])]) m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])]) # pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- # serial 1 (pkg-config-0.24) # # Copyright © 2004 Scott James Remnant . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # PKG_PROG_PKG_CONFIG([MIN-VERSION]) # ---------------------------------- AC_DEFUN([PKG_PROG_PKG_CONFIG], [m4_pattern_forbid([^_?PKG_[A-Z_]+$]) m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) fi if test -n "$PKG_CONFIG"; then _pkg_min_version=m4_default([$1], [0.9.0]) AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) PKG_CONFIG="" fi fi[]dnl ])# PKG_PROG_PKG_CONFIG # PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # # Check to see whether a particular set of modules exists. Similar # to PKG_CHECK_MODULES(), but does not set variables or print errors. # # Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) # only at the first occurence in configure.ac, so if the first place # it's called might be skipped (such as if it is within an "if", you # have to call PKG_CHECK_EXISTS manually # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_EXISTS], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl if test -n "$PKG_CONFIG" && \ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then m4_default([$2], [:]) m4_ifvaln([$3], [else $3])dnl fi]) # _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) # --------------------------------------------- m4_define([_PKG_CONFIG], [if test -n "$$1"; then pkg_cv_[]$1="$$1" elif test -n "$PKG_CONFIG"; then PKG_CHECK_EXISTS([$3], [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes ], [pkg_failed=yes]) else pkg_failed=untried fi[]dnl ])# _PKG_CONFIG # _PKG_SHORT_ERRORS_SUPPORTED # ----------------------------- AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], [AC_REQUIRE([PKG_PROG_PKG_CONFIG]) if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi[]dnl ])# _PKG_SHORT_ERRORS_SUPPORTED # PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], # [ACTION-IF-NOT-FOUND]) # # # Note that if there is a possibility the first call to # PKG_CHECK_MODULES might not happen, you should be sure to include an # explicit call to PKG_PROG_PKG_CONFIG in your configure.ac # # # -------------------------------------------------------------- AC_DEFUN([PKG_CHECK_MODULES], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl pkg_failed=no AC_MSG_CHECKING([for $1]) _PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) _PKG_CONFIG([$1][_LIBS], [libs], [$2]) m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS and $1[]_LIBS to avoid the need to call pkg-config. See the pkg-config man page for more details.]) if test $pkg_failed = yes; then AC_MSG_RESULT([no]) _PKG_SHORT_ERRORS_SUPPORTED if test $_pkg_short_errors_supported = yes; then $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` else $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD m4_default([$4], [AC_MSG_ERROR( [Package requirements ($2) were not met: $$1_PKG_ERRORS Consider adjusting the PKG_CONFIG_PATH environment variable if you installed software in a non-standard prefix. _PKG_TEXT])[]dnl ]) elif test $pkg_failed = untried; then AC_MSG_RESULT([no]) m4_default([$4], [AC_MSG_FAILURE( [The pkg-config script could not be found or is too old. Make sure it is in your PATH or set the PKG_CONFIG environment variable to the full path to pkg-config. _PKG_TEXT To get pkg-config, see .])[]dnl ]) else $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS $1[]_LIBS=$pkg_cv_[]$1[]_LIBS AC_MSG_RESULT([yes]) $3 fi[]dnl ])# PKG_CHECK_MODULES # Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008, 2011 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.11' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.11.3], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.11.3])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to # `$srcdir', `$srcdir/..', or `$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is `.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 9 # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ(2.52)dnl ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009, # 2010, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 12 # There are a few dirty hacks below to avoid letting `AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "GCJ", or "OBJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl ifelse([$1], CC, [depcc="$CC" am_compiler_list=], [$1], CXX, [depcc="$CXX" am_compiler_list=], [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], UPC, [depcc="$UPC" am_compiler_list=], [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE(dependency-tracking, [ --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. #serial 5 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each `.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 8 # AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2008, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 16 # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.62])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) AM_MISSING_PROG(AUTOCONF, autoconf) AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) AM_MISSING_PROG(AUTOHEADER, autoheader) AM_MISSING_PROG(MAKEINFO, makeinfo) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AM_PROG_MKDIR_P])dnl # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES(CC)], [define([AC_PROG_CC], defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES(CXX)], [define([AC_PROG_CXX], defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES(OBJC)], [define([AC_PROG_OBJC], defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl ]) _AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl dnl The `parallel-tests' driver may need to know about EXEEXT, so add the dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl ]) dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001, 2003, 2005, 2008, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST(install_sh)]) # Copyright (C) 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_PROG_LEX # ----------- # Autoconf leaves LEX=: if lex or flex can't be found. Change that to a # "missing" invocation, for better error output. AC_DEFUN([AM_PROG_LEX], [AC_PREREQ(2.50)dnl AC_REQUIRE([AM_MISSING_HAS_RUN])dnl AC_REQUIRE([AC_PROG_LEX])dnl if test "$LEX" = :; then LEX=${am_missing_run}flex fi]) # Add --enable-maintainer-mode option to configure. -*- Autoconf -*- # From Jim Meyering # Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, # 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_MAINTAINER_MODE([DEFAULT-MODE]) # ---------------------------------- # Control maintainer-specific portions of Makefiles. # Default is to disable them, unless `enable' is passed literally. # For symmetry, `disable' may be passed as well. Anyway, the user # can override the default with the --enable/--disable switch. AC_DEFUN([AM_MAINTAINER_MODE], [m4_case(m4_default([$1], [disable]), [enable], [m4_define([am_maintainer_other], [disable])], [disable], [m4_define([am_maintainer_other], [enable])], [m4_define([am_maintainer_other], [enable]) m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles]) dnl maintainer-mode's default is 'disable' unless 'enable' is passed AC_ARG_ENABLE([maintainer-mode], [ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful (and sometimes confusing) to the casual installer], [USE_MAINTAINER_MODE=$enableval], [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) AC_MSG_RESULT([$USE_MAINTAINER_MODE]) AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) MAINT=$MAINTAINER_MODE_TRUE AC_SUBST([MAINT])dnl ] ) AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 4 # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_PROG_CC_C_O # -------------- # Like AC_PROG_CC_C_O, but changed for automake. AC_DEFUN([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC_C_O])dnl AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi dnl Make sure AC_PROG_CC is never called again, or it will override our dnl setting of CC. m4_define([AC_PROG_CC], [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 6 # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it supports --run. # If it does, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= AC_MSG_WARN([`missing' script is too old or missing]) fi ]) # Copyright (C) 2003, 2004, 2005, 2006, 2011 Free Software Foundation, # Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_MKDIR_P # --------------- # Check for `mkdir -p'. AC_DEFUN([AM_PROG_MKDIR_P], [AC_PREREQ([2.60])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, dnl while keeping a definition of mkdir_p for backward compatibility. dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of dnl Makefile.ins that do not define MKDIR_P, so we do our own dnl adjustment using top_builddir (which is defined more often than dnl MKDIR_P). AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl case $mkdir_p in [[\\/$]]* | ?:[[\\/]]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac ]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001, 2002, 2003, 2005, 2008, 2010 Free Software # Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), 1)]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 5 # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT(yes)]) # Copyright (C) 2009, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # (`yes' being less verbose, `no' or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [ --enable-silent-rules less verbose build output (undo: `make V=1') --disable-silent-rules verbose build output (undo: `make V=0')]) case $enable_silent_rules in yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few `make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using `$V' instead of `$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 1 # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor `install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in `make install-strip', and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be `maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006, 2008, 2010 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 3 # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004, 2005, 2012 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # serial 2 # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of `v7', `ustar', or `pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar],, [pax],, [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' _am_tools=${am_cv_prog_tar_$1-$_am_tools} # Do not fold the above two line into one, because Tru64 sh and # Solaris sh will not grok spaces in the rhs of `-'. for _am_tool in $_am_tools do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR m4_include([acinclude.m4]) bluez-4.101/depcomp0000755000000000000000000004755611771117506011133 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2011-12-04.11; # UTC # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010, # 2011 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program 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 General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try \`$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by `PROGRAMS ARGS'. object Object file output by `PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ## The second -e expression handles DOS-style file names with drive letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the `deleted header file' problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. tr ' ' ' ' < "$tmpdepfile" | ## Some versions of gcc put a space before the `:'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like `#:fec' to the end of the # dependency line. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ tr ' ' ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' ' ' < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts `$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then # Each line is of the form `foo.o: dependent.h'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else # The sourcefile does not contain any dependencies, so just # store a dummy comment line, to avoid errors with the Makefile # "include basename.Plo" scheme. echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; icc) # Intel's C compiler understands `-MD -MF file'. However on # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c # ICC 7.0 will fill foo.d with something like # foo.o: sub/foo.c # foo.o: sub/foo.h # which is wrong. We want: # sub/foo.o: sub/foo.c # sub/foo.o: sub/foo.h # sub/foo.c: # sub/foo.h: # ICC 7.1 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using \ : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" # Add `dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in `foo.d' instead, so we check for that too. # Subdirectories are respected. dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` test "x$dir" = "x$object" && dir= base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` if test "$libtool" = yes; then # With Tru64 cc, shared objects can also be used to make a # static library. This mechanism is used in libtool 1.4 series to # handle both shared and static libraries in a single compilation. # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. # # With libtool 1.5 this exception was removed, and libtool now # generates 2 separate objects for the 2 libraries. These two # compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 tmpdepfile2=$dir$base.o.d # libtool 1.5 tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.o.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d tmpdepfile4=$dir$base.d "$@" -MD fi stat=$? if test $stat -eq 0; then : else rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" # That's a tab and a space in the []. sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" else echo "#dummy" > "$depfile" fi rm -f "$tmpdepfile" ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test "$stat" = 0; then : else rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/ \1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/ / G p }' >> "$depfile" rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for `:' # in the target name. This is to cope with DOS-style filenames: # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. "$@" $dashmflag | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" tr ' ' ' ' < "$tmpdepfile" | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" sed '1,2d' "$tmpdepfile" | tr ' ' ' ' | \ ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove `-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" echo " " >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: bluez-4.101/INSTALL0000644000000000000000000002240611071665350010570 00000000000000Installation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' will install the package's files in `/usr/local/bin', `/usr/local/man', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you give `configure' the option `--exec-prefix=PREFIX', the package will use PREFIX as the prefix for installing programs and libraries. Documentation and other data files will still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the `--target=TYPE' option to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Here is a another example: /bin/bash ./configure CONFIG_SHELL=/bin/bash Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent configuration-related scripts to be executed by `/bin/bash'. `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. bluez-4.101/deviceinfo/0000755000000000000000000000000011771120004011713 500000000000000bluez-4.101/deviceinfo/deviceinfo.h0000644000000000000000000000171511766125764014151 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim); void deviceinfo_unregister(struct btd_device *device); bluez-4.101/deviceinfo/deviceinfo.c0000644000000000000000000001102011766125764014132 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "adapter.h" #include "device.h" #include "gattrib.h" #include "attio.h" #include "att.h" #include "gattrib.h" #include "gatt.h" #include "log.h" #include "deviceinfo.h" struct deviceinfo { struct btd_device *dev; /* Device reference */ GAttrib *attrib; /* GATT connection */ guint attioid; /* Att watcher id */ struct att_range *svc_range; /* DeviceInfo range */ GSList *chars; /* Characteristics */ }; static GSList *servers = NULL; struct characteristic { struct gatt_char attr; /* Characteristic */ struct deviceinfo *d; /* deviceinfo where the char belongs */ }; static void deviceinfo_free(gpointer user_data) { struct deviceinfo *d = user_data; 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 gint cmp_device(gconstpointer a, gconstpointer b) { const struct deviceinfo *d = a; const struct btd_device *dev = b; if (dev == d->dev) return 0; return -1; } static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct characteristic *ch = user_data; uint8_t value[ATT_MAX_MTU]; int vlen; if (status != 0) { error("Error reading PNP_ID value: %s", att_ecode2str(status)); return; } if (!dec_read_resp(pdu, len, value, &vlen)) { error("Error reading PNP_ID: Protocol error"); return; } if (vlen < 7) { error("Error reading PNP_ID: Invalid pdu length received"); return; } device_set_pnpid(ch->d->dev, value[0], att_get_u16(&value[1]), att_get_u16(&value[3]), att_get_u16(&value[5])); } static void process_deviceinfo_char(struct characteristic *ch) { if (g_strcmp0(ch->attr.uuid, PNPID_UUID) == 0) gatt_read_char(ch->d->attrib, ch->attr.value_handle, 0, read_pnpid_cb, ch); } static void configure_deviceinfo_cb(GSList *characteristics, guint8 status, gpointer user_data) { struct deviceinfo *d = user_data; GSList *l; if (status != 0) { error("Discover deviceinfo characteristics: %s", att_ecode2str(status)); return; } for (l = characteristics; l; l = l->next) { struct gatt_char *c = l->data; struct characteristic *ch; ch = g_new0(struct characteristic, 1); ch->attr.handle = c->handle; ch->attr.properties = c->properties; ch->attr.value_handle = c->value_handle; memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1); ch->d = d; d->chars = g_slist_append(d->chars, ch); process_deviceinfo_char(ch); } } static void attio_connected_cb(GAttrib *attrib, gpointer user_data) { struct deviceinfo *d = user_data; d->attrib = g_attrib_ref(attrib); gatt_discover_char(d->attrib, d->svc_range->start, d->svc_range->end, NULL, configure_deviceinfo_cb, d); } static void attio_disconnected_cb(gpointer user_data) { struct deviceinfo *d = user_data; g_attrib_unref(d->attrib); d->attrib = NULL; } int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim) { struct deviceinfo *d; d = g_new0(struct deviceinfo, 1); d->dev = btd_device_ref(device); d->svc_range = g_new0(struct att_range, 1); d->svc_range->start = prim->range.start; d->svc_range->end = prim->range.end; servers = g_slist_prepend(servers, d); d->attioid = btd_device_add_attio_callback(device, attio_connected_cb, attio_disconnected_cb, d); return 0; } void deviceinfo_unregister(struct btd_device *device) { struct deviceinfo *d; GSList *l; l = g_slist_find_custom(servers, device, cmp_device); if (l == NULL) return; d = l->data; servers = g_slist_remove(servers, d); deviceinfo_free(d); } bluez-4.101/deviceinfo/main.c0000644000000000000000000000255011766125764012753 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "plugin.h" #include "manager.h" #include "hcid.h" #include "log.h" static int deviceinfo_init(void) { if (!main_opts.gatt_enabled) { error("DIS cannot start: GATT is disabled"); return -ENOTSUP; } return deviceinfo_manager_init(); } static void deviceinfo_exit(void) { deviceinfo_manager_exit(); } BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, deviceinfo_init, deviceinfo_exit) bluez-4.101/deviceinfo/manager.h0000644000000000000000000000161611766125764013450 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int deviceinfo_manager_init(void); void deviceinfo_manager_exit(void); bluez-4.101/deviceinfo/manager.c0000644000000000000000000000405511766125764013443 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include "adapter.h" #include "device.h" #include "att.h" #include "gattrib.h" #include "gatt.h" #include "deviceinfo.h" #include "manager.h" static gint primary_uuid_cmp(gconstpointer a, gconstpointer b) { const struct gatt_primary *prim = a; const char *uuid = b; return g_strcmp0(prim->uuid, uuid); } static int deviceinfo_driver_probe(struct btd_device *device, GSList *uuids) { struct gatt_primary *prim; GSList *primaries, *l; primaries = btd_device_get_primaries(device); l = g_slist_find_custom(primaries, DEVICE_INFORMATION_UUID, primary_uuid_cmp); if (l == NULL) return -EINVAL; prim = l->data; return deviceinfo_register(device, prim); } static void deviceinfo_driver_remove(struct btd_device *device) { deviceinfo_unregister(device); } static struct btd_device_driver deviceinfo_device_driver = { .name = "deviceinfo-driver", .uuids = BTD_UUIDS(DEVICE_INFORMATION_UUID), .probe = deviceinfo_driver_probe, .remove = deviceinfo_driver_remove }; int deviceinfo_manager_init(void) { return btd_register_device_driver(&deviceinfo_device_driver); } void deviceinfo_manager_exit(void) { btd_unregister_device_driver(&deviceinfo_device_driver); } bluez-4.101/Makefile.tools0000644000000000000000000001634511771117441012343 00000000000000 if TOOLS if DATAFILES conf_DATA += tools/rfcomm.conf endif bin_PROGRAMS += tools/rfcomm tools/l2ping \ tools/hcitool tools/sdptool tools/ciptool sbin_PROGRAMS += tools/hciattach tools/hciconfig noinst_PROGRAMS += tools/avinfo tools/ppporc \ tools/hcieventmask tools/hcisecfilter tools/kword.c: tools/parser.h tools_rfcomm_SOURCES = tools/rfcomm.c tools/parser.y tools/lexer.l \ tools/kword.h tools/kword.c EXTRA_tools_rfcomm_SOURCES = tools/parser.h tools/parser.c \ tools/lexer.c tools_rfcomm_LDADD = lib/libbluetooth-private.la tools_l2ping_LDADD = lib/libbluetooth-private.la tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \ tools/hciattach_st.c \ tools/hciattach_ti.c \ tools/hciattach_tialt.c \ tools/hciattach_ath3k.c \ tools/hciattach_qualcomm.c \ tools/hciattach_intel.c tools_hciattach_LDADD = lib/libbluetooth-private.la tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \ src/textfile.h src/textfile.c tools_hciconfig_LDADD = lib/libbluetooth-private.la tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c \ src/textfile.h src/textfile.c tools_hcitool_LDADD = lib/libbluetooth-private.la tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c tools_sdptool_LDADD = lib/libbluetooth-private.la tools_ciptool_LDADD = lib/libbluetooth-private.la tools_avinfo_LDADD = lib/libbluetooth-private.la tools_ppporc_LDADD = lib/libbluetooth-private.la tools_hcieventmask_LDADD = lib/libbluetooth-private.la noinst_PROGRAMS += mgmt/btmgmt monitor/btmon emulator/btvirt mgmt_btmgmt_SOURCES = mgmt/main.c src/glib-helper.c mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \ monitor/mainloop.h monitor/mainloop.c \ monitor/hcidump.h monitor/hcidump.c \ monitor/btsnoop.h monitor/btsnoop.c \ monitor/control.h monitor/control.c \ monitor/packet.h monitor/packet.c monitor_btmon_LDADD = lib/libbluetooth-private.la emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \ monitor/mainloop.h monitor/mainloop.c \ emulator/server.h emulator/server.c \ emulator/vhci.h emulator/vhci.c \ emulator/btdev.h emulator/btdev.c if READLINE bin_PROGRAMS += attrib/gatttool attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \ attrib/gattrib.c btio/btio.c \ attrib/gatttool.h attrib/interactive.c \ attrib/utils.c src/log.c attrib_gatttool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @READLINE_LIBS@ endif dist_man_MANS += tools/rfcomm.1 tools/l2ping.8 \ tools/hciattach.8 tools/hciconfig.8 \ tools/hcitool.1 tools/sdptool.1 tools/ciptool.1 else EXTRA_DIST += tools/rfcomm.1 tools/l2ping.8 \ tools/hciattach.8 tools/hciconfig.8 \ tools/hcitool.1 tools/sdptool.1 tools/ciptool.1 endif CLEANFILES += tools/lexer.c tools/parser.c tools/parser.h EXTRA_DIST += tools/rfcomm.conf if BCCMD sbin_PROGRAMS += tools/bccmd tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h tools/csr.c \ tools/csr_hci.c tools/csr_h4.c tools/csr_3wire.c \ tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c tools_bccmd_LDADD = lib/libbluetooth-private.la if USB tools_bccmd_SOURCES += tools/csr_usb.c tools_bccmd_LDADD += @USB_LIBS@ endif dist_man_MANS += tools/bccmd.8 else EXTRA_DIST += tools/bccmd.8 endif if HID2HCI udevdir = @UDEV_DIR@ udev_PROGRAMS = tools/hid2hci tools_hid2hci_LDADD = @USB_LIBS@ @UDEV_LIBS@ dist_man_MANS += tools/hid2hci.8 else EXTRA_DIST += tools/hid2hci.8 endif if DFUTOOL bin_PROGRAMS += tools/dfutool tools_dfutool_SOURCES = tools/dfutool.c tools/dfu.h tools/dfu.c tools_dfutool_LDADD = @USB_LIBS@ dist_man_MANS += tools/dfutool.1 else EXTRA_DIST += tools/dfutool.1 endif if USB noinst_PROGRAMS += tools/dfubabel tools/avctrl tools_dfubabel_LDADD = @USB_LIBS@ tools_avctrl_LDADD = @USB_LIBS@ endif EXTRA_DIST += tools/dfubabel.1 tools/avctrl.8 if CUPS cupsdir = $(libdir)/cups/backend cups_PROGRAMS = cups/bluetooth cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \ cups/sdp.c cups/spp.c cups/hcrp.c cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth-private.la endif if TEST sbin_PROGRAMS += test/hciemu bin_PROGRAMS += test/l2test test/rctest noinst_PROGRAMS += test/gaptest test/sdptest test/scotest \ test/attest test/hstest test/avtest test/ipctest \ test/lmptest test/bdaddr test/agent \ test/btiotest test/test-textfile \ test/uuidtest test/mpris-player test_hciemu_LDADD = lib/libbluetooth-private.la test_l2test_LDADD = lib/libbluetooth-private.la test_rctest_LDADD = lib/libbluetooth-private.la test_gaptest_LDADD = @DBUS_LIBS@ test_sdptest_LDADD = lib/libbluetooth-private.la test_scotest_LDADD = lib/libbluetooth-private.la test_attest_LDADD = lib/libbluetooth-private.la test_hstest_LDADD = lib/libbluetooth-private.la test_avtest_LDADD = lib/libbluetooth-private.la test_lmptest_LDADD = lib/libbluetooth-private.la test_ipctest_SOURCES = test/ipctest.c audio/ipc.h audio/ipc.c test_ipctest_LDADD= @GLIB_LIBS@ sbc/libsbc.la test_bdaddr_SOURCES = test/bdaddr.c src/oui.h src/oui.c test_bdaddr_LDADD = lib/libbluetooth-private.la test_agent_LDADD = @DBUS_LIBS@ test_btiotest_SOURCES = test/btiotest.c btio/btio.h btio/btio.c test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la test_uuidtest_SOURCES = test/uuidtest.c test_uuidtest_LDADD = lib/libbluetooth-private.la test_mpris_player_SOURCES = test/mpris-player.c test_mpris_player_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c dist_man_MANS += test/rctest.1 test/hciemu.1 EXTRA_DIST += test/bdaddr.8 else EXTRA_DIST += test/rctest.1 test/hciemu.1 test/bdaddr.8 endif EXTRA_DIST += test/sap-client test/hsplay test/hsmicro \ test/dbusdef.py test/monitor-bluetooth test/list-devices \ test/test-discovery test/test-manager test/test-adapter \ test/test-device test/test-service test/test-serial \ test/test-telephony test/test-network test/simple-agent \ test/simple-service test/simple-endpoint test/test-audio \ test/test-input test/test-sap-server test/test-oob \ test/test-attrib test/test-proximity test/test-thermometer \ test/test-serial-proxy test/test-health test/test-health-sink \ test/service-record.dtd test/service-did.xml \ test/service-spp.xml test/service-opp.xml test/service-ftp.xml \ test/simple-player test/test-nap if HIDD bin_PROGRAMS += compat/hidd compat_hidd_SOURCES = compat/hidd.c compat/hidd.h src/uinput.h \ compat/sdp.h compat/sdp.c compat/fakehid.c \ src/textfile.h src/textfile.c compat_hidd_LDADD = -lm lib/libbluetooth-private.la dist_man_MANS += compat/hidd.1 else EXTRA_DIST += compat/hidd.1 endif if PAND bin_PROGRAMS += compat/pand compat_pand_SOURCES = compat/pand.c compat/pand.h \ compat/bnep.c compat/sdp.h compat/sdp.c \ src/textfile.h src/textfile.c compat_pand_LDADD = lib/libbluetooth-private.la dist_man_MANS += compat/pand.1 else EXTRA_DIST += compat/pand.1 endif if DUND bin_PROGRAMS += compat/dund compat_dund_SOURCES = compat/dund.c compat/dund.h compat/lib.h \ compat/sdp.h compat/sdp.c compat/dun.c compat/msdun.c \ src/textfile.h src/textfile.c compat_dund_LDADD = lib/libbluetooth-private.la dist_man_MANS += compat/dund.1 else EXTRA_DIST += compat/dund.1 endif bluez-4.101/config.h.in0000644000000000000000000000452511771117503011563 00000000000000/* config.h.in. Generated from configure.ac by autoheader. */ /* Directory for the configuration files */ #undef CONFIGDIR /* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have USB library. */ #undef HAVE_LIBUSB /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* Define to 1 if you have . */ #undef HAVE_SYS_INOTIFY_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Define to the sub-directory in which libtool stores uninstalled libraries. */ #undef LT_OBJDIR /* Define to 1 if you need the ppoll() function. */ #undef NEED_PPOLL /* Define to 1 if you need the usb_get_busses() function. */ #undef NEED_USB_GET_BUSSES /* Define to 1 if you need the usb_interrupt_read() function. */ #undef NEED_USB_INTERRUPT_READ /* Define to 1 if your C compiler doesn't accept -c and -o together. */ #undef NO_MINUS_C_MINUS_O /* Define the OUI file path */ #undef OUIFILE /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Directory for the storage files */ #undef STORAGEDIR /* Version number of package */ #undef VERSION /* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a `char[]'. */ #undef YYTEXT_POINTER bluez-4.101/btio/0000755000000000000000000000000011771120004010535 500000000000000bluez-4.101/btio/btio.c0000644000000000000000000010010011766125764011574 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2009-2010 Marcel Holtmann * Copyright (C) 2009-2010 Nokia Corporation * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "btio.h" #ifndef BT_FLUSHABLE #define BT_FLUSHABLE 8 #endif #define ERROR_FAILED(gerr, str, err) \ g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \ str ": %s (%d)", strerror(err), err) #define DEFAULT_DEFER_TIMEOUT 30 struct set_opts { bdaddr_t src; bdaddr_t dst; uint8_t dst_type; int defer; int sec_level; uint8_t channel; uint16_t psm; uint16_t cid; uint16_t mtu; uint16_t imtu; uint16_t omtu; int master; uint8_t mode; int flushable; uint32_t priority; }; struct connect { BtIOConnect connect; gpointer user_data; GDestroyNotify destroy; }; struct accept { BtIOConnect connect; gpointer user_data; GDestroyNotify destroy; }; struct server { BtIOConnect connect; BtIOConfirm confirm; gpointer user_data; GDestroyNotify destroy; }; static void server_remove(struct server *server) { if (server->destroy) server->destroy(server->user_data); g_free(server); } static void connect_remove(struct connect *conn) { if (conn->destroy) conn->destroy(conn->user_data); g_free(conn); } static void accept_remove(struct accept *accept) { if (accept->destroy) accept->destroy(accept->user_data); g_free(accept); } static gboolean check_nval(GIOChannel *io) { struct pollfd fds; memset(&fds, 0, sizeof(fds)); fds.fd = g_io_channel_unix_get_fd(io); fds.events = POLLNVAL; if (poll(&fds, 1, 0) > 0 && (fds.revents & POLLNVAL)) return TRUE; return FALSE; } static gboolean accept_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct accept *accept = user_data; GError *err = NULL; /* If the user aborted this accept attempt */ if ((cond & G_IO_NVAL) || check_nval(io)) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED, "HUP or ERR on socket"); accept->connect(io, err, accept->user_data); g_clear_error(&err); return FALSE; } static gboolean connect_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct connect *conn = user_data; GError *gerr = NULL; /* If the user aborted this connect attempt */ if ((cond & G_IO_NVAL) || check_nval(io)) return FALSE; if (cond & G_IO_OUT) { int err, sk_err = 0, sock = g_io_channel_unix_get_fd(io); socklen_t len = sizeof(sk_err); if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0) err = -errno; else err = -sk_err; if (err < 0) g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED, "%s (%d)", strerror(-err), -err); } else if (cond & (G_IO_HUP | G_IO_ERR)) g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED, "HUP or ERR on socket"); conn->connect(io, gerr, conn->user_data); if (gerr) g_error_free(gerr); return FALSE; } static gboolean server_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct server *server = user_data; int srv_sock, cli_sock; GIOChannel *cli_io; /* If the user closed the server */ if ((cond & G_IO_NVAL) || check_nval(io)) return FALSE; srv_sock = g_io_channel_unix_get_fd(io); cli_sock = accept(srv_sock, NULL, NULL); if (cli_sock < 0) return TRUE; cli_io = g_io_channel_unix_new(cli_sock); g_io_channel_set_close_on_unref(cli_io, TRUE); g_io_channel_set_flags(cli_io, G_IO_FLAG_NONBLOCK, NULL); if (server->confirm) server->confirm(cli_io, server->user_data); else server->connect(cli_io, NULL, server->user_data); g_io_channel_unref(cli_io); return TRUE; } static void server_add(GIOChannel *io, BtIOConnect connect, BtIOConfirm confirm, gpointer user_data, GDestroyNotify destroy) { struct server *server; GIOCondition cond; server = g_new0(struct server, 1); server->connect = connect; server->confirm = confirm; server->user_data = user_data; server->destroy = destroy; cond = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL; g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, server_cb, server, (GDestroyNotify) server_remove); } static void connect_add(GIOChannel *io, BtIOConnect connect, gpointer user_data, GDestroyNotify destroy) { struct connect *conn; GIOCondition cond; conn = g_new0(struct connect, 1); conn->connect = connect; conn->user_data = user_data; conn->destroy = destroy; cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL; g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, connect_cb, conn, (GDestroyNotify) connect_remove); } static void accept_add(GIOChannel *io, BtIOConnect connect, gpointer user_data, GDestroyNotify destroy) { struct accept *accept; GIOCondition cond; accept = g_new0(struct accept, 1); accept->connect = connect; accept->user_data = user_data; accept->destroy = destroy; cond = G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL; g_io_add_watch_full(io, G_PRIORITY_DEFAULT, cond, accept_cb, accept, (GDestroyNotify) accept_remove); } static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm, uint16_t cid, GError **err) { struct sockaddr_l2 addr; memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; bacpy(&addr.l2_bdaddr, src); if (cid) addr.l2_cid = htobs(cid); else addr.l2_psm = htobs(psm); if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { int error = -errno; ERROR_FAILED(err, "l2cap_bind", errno); return error; } return 0; } static int l2cap_connect(int sock, const bdaddr_t *dst, uint8_t dst_type, uint16_t psm, uint16_t cid) { int err; struct sockaddr_l2 addr; memset(&addr, 0, sizeof(addr)); addr.l2_family = AF_BLUETOOTH; bacpy(&addr.l2_bdaddr, dst); if (cid) addr.l2_cid = htobs(cid); else addr.l2_psm = htobs(psm); addr.l2_bdaddr_type = dst_type; err = connect(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) return -errno; return 0; } static int l2cap_set_master(int sock, int master) { int flags; socklen_t len; len = sizeof(flags); if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len) < 0) return -errno; if (master) { if (flags & L2CAP_LM_MASTER) return 0; flags |= L2CAP_LM_MASTER; } else { if (!(flags & L2CAP_LM_MASTER)) return 0; flags &= ~L2CAP_LM_MASTER; } if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, sizeof(flags)) < 0) return -errno; return 0; } static int rfcomm_set_master(int sock, int master) { int flags; socklen_t len; len = sizeof(flags); if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, &len) < 0) return -errno; if (master) { if (flags & RFCOMM_LM_MASTER) return 0; flags |= RFCOMM_LM_MASTER; } else { if (!(flags & RFCOMM_LM_MASTER)) return 0; flags &= ~RFCOMM_LM_MASTER; } if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, sizeof(flags)) < 0) return -errno; return 0; } static int l2cap_set_lm(int sock, int level) { int lm_map[] = { 0, L2CAP_LM_AUTH, L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT, L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE, }, opt = lm_map[level]; if (setsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) return -errno; return 0; } static int rfcomm_set_lm(int sock, int level) { int lm_map[] = { 0, RFCOMM_LM_AUTH, RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT, RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE, }, opt = lm_map[level]; if (setsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, sizeof(opt)) < 0) return -errno; return 0; } static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err) { struct bt_security sec; int ret; if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) { g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Valid security level range is %d-%d", BT_SECURITY_LOW, BT_SECURITY_HIGH); return FALSE; } memset(&sec, 0, sizeof(sec)); sec.level = level; if (setsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, sizeof(sec)) == 0) return TRUE; if (errno != ENOPROTOOPT) { ERROR_FAILED(err, "setsockopt(BT_SECURITY)", errno); return FALSE; } if (type == BT_IO_L2CAP) ret = l2cap_set_lm(sock, level); else ret = rfcomm_set_lm(sock, level); if (ret < 0) { ERROR_FAILED(err, "setsockopt(LM)", -ret); return FALSE; } return TRUE; } static int l2cap_get_lm(int sock, int *sec_level) { int opt; socklen_t len; len = sizeof(opt); if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &opt, &len) < 0) return -errno; *sec_level = 0; if (opt & L2CAP_LM_AUTH) *sec_level = BT_SECURITY_LOW; if (opt & L2CAP_LM_ENCRYPT) *sec_level = BT_SECURITY_MEDIUM; if (opt & L2CAP_LM_SECURE) *sec_level = BT_SECURITY_HIGH; return 0; } static int rfcomm_get_lm(int sock, int *sec_level) { int opt; socklen_t len; len = sizeof(opt); if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &opt, &len) < 0) return -errno; *sec_level = 0; if (opt & RFCOMM_LM_AUTH) *sec_level = BT_SECURITY_LOW; if (opt & RFCOMM_LM_ENCRYPT) *sec_level = BT_SECURITY_MEDIUM; if (opt & RFCOMM_LM_SECURE) *sec_level = BT_SECURITY_HIGH; return 0; } static gboolean get_sec_level(int sock, BtIOType type, int *level, GError **err) { struct bt_security sec; socklen_t len; int ret; memset(&sec, 0, sizeof(sec)); len = sizeof(sec); if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) { *level = sec.level; return TRUE; } if (errno != ENOPROTOOPT) { ERROR_FAILED(err, "getsockopt(BT_SECURITY)", errno); return FALSE; } if (type == BT_IO_L2CAP) ret = l2cap_get_lm(sock, level); else ret = rfcomm_get_lm(sock, level); if (ret < 0) { ERROR_FAILED(err, "getsockopt(LM)", -ret); return FALSE; } return TRUE; } static int l2cap_set_flushable(int sock, gboolean flushable) { int f; f = flushable; if (setsockopt(sock, SOL_BLUETOOTH, BT_FLUSHABLE, &f, sizeof(f)) < 0) return -errno; return 0; } static int set_priority(int sock, uint32_t prio) { if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0) return -errno; return 0; } static gboolean get_key_size(int sock, int *size, GError **err) { struct bt_security sec; socklen_t len; memset(&sec, 0, sizeof(sec)); len = sizeof(sec); if (getsockopt(sock, SOL_BLUETOOTH, BT_SECURITY, &sec, &len) == 0) { *size = sec.key_size; return TRUE; } return FALSE; } static gboolean l2cap_set(int sock, int sec_level, uint16_t imtu, uint16_t omtu, uint8_t mode, int master, int flushable, uint32_t priority, GError **err) { if (imtu || omtu || mode) { struct l2cap_options l2o; socklen_t len; memset(&l2o, 0, sizeof(l2o)); len = sizeof(l2o); if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) { ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno); return FALSE; } if (imtu) l2o.imtu = imtu; if (omtu) l2o.omtu = omtu; if (mode) l2o.mode = mode; if (setsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) { ERROR_FAILED(err, "setsockopt(L2CAP_OPTIONS)", errno); return FALSE; } } if (master >= 0 && l2cap_set_master(sock, master) < 0) { ERROR_FAILED(err, "l2cap_set_master", errno); return FALSE; } if (flushable >= 0 && l2cap_set_flushable(sock, flushable) < 0) { ERROR_FAILED(err, "l2cap_set_flushable", errno); return FALSE; } if (priority > 0 && set_priority(sock, priority) < 0) { ERROR_FAILED(err, "set_priority", errno); return FALSE; } if (sec_level && !set_sec_level(sock, BT_IO_L2CAP, sec_level, err)) return FALSE; return TRUE; } static int rfcomm_bind(int sock, const bdaddr_t *src, uint8_t channel, GError **err) { struct sockaddr_rc addr; memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, src); addr.rc_channel = channel; if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { int error = -errno; ERROR_FAILED(err, "rfcomm_bind", errno); return error; } return 0; } static int rfcomm_connect(int sock, const bdaddr_t *dst, uint8_t channel) { int err; struct sockaddr_rc addr; memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, dst); addr.rc_channel = channel; err = connect(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) return -errno; return 0; } static gboolean rfcomm_set(int sock, int sec_level, int master, GError **err) { if (sec_level && !set_sec_level(sock, BT_IO_RFCOMM, sec_level, err)) return FALSE; if (master >= 0 && rfcomm_set_master(sock, master) < 0) { ERROR_FAILED(err, "rfcomm_set_master", errno); return FALSE; } return TRUE; } static int sco_bind(int sock, const bdaddr_t *src, GError **err) { struct sockaddr_sco addr; memset(&addr, 0, sizeof(addr)); addr.sco_family = AF_BLUETOOTH; bacpy(&addr.sco_bdaddr, src); if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) { int error = -errno; ERROR_FAILED(err, "sco_bind", errno); return error; } return 0; } static int sco_connect(int sock, const bdaddr_t *dst) { struct sockaddr_sco addr; int err; memset(&addr, 0, sizeof(addr)); addr.sco_family = AF_BLUETOOTH; bacpy(&addr.sco_bdaddr, dst); err = connect(sock, (struct sockaddr *) &addr, sizeof(addr)); if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) return -errno; return 0; } static gboolean sco_set(int sock, uint16_t mtu, GError **err) { struct sco_options sco_opt; socklen_t len; if (!mtu) return TRUE; len = sizeof(sco_opt); memset(&sco_opt, 0, len); if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) { ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno); return FALSE; } sco_opt.mtu = mtu; if (setsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, sizeof(sco_opt)) < 0) { ERROR_FAILED(err, "setsockopt(SCO_OPTIONS)", errno); return FALSE; } return TRUE; } static gboolean parse_set_opts(struct set_opts *opts, GError **err, BtIOOption opt1, va_list args) { BtIOOption opt = opt1; const char *str; memset(opts, 0, sizeof(*opts)); /* Set defaults */ opts->defer = DEFAULT_DEFER_TIMEOUT; opts->master = -1; opts->mode = L2CAP_MODE_BASIC; opts->flushable = -1; opts->priority = 0; opts->dst_type = BDADDR_BREDR; while (opt != BT_IO_OPT_INVALID) { switch (opt) { case BT_IO_OPT_SOURCE: str = va_arg(args, const char *); str2ba(str, &opts->src); break; case BT_IO_OPT_SOURCE_BDADDR: bacpy(&opts->src, va_arg(args, const bdaddr_t *)); break; case BT_IO_OPT_DEST: str2ba(va_arg(args, const char *), &opts->dst); break; case BT_IO_OPT_DEST_BDADDR: bacpy(&opts->dst, va_arg(args, const bdaddr_t *)); break; case BT_IO_OPT_DEST_TYPE: opts->dst_type = va_arg(args, int); break; case BT_IO_OPT_DEFER_TIMEOUT: opts->defer = va_arg(args, int); break; case BT_IO_OPT_SEC_LEVEL: opts->sec_level = va_arg(args, int); break; case BT_IO_OPT_CHANNEL: opts->channel = va_arg(args, int); break; case BT_IO_OPT_PSM: opts->psm = va_arg(args, int); break; case BT_IO_OPT_CID: opts->cid = va_arg(args, int); break; case BT_IO_OPT_MTU: opts->mtu = va_arg(args, int); opts->imtu = opts->mtu; opts->omtu = opts->mtu; break; case BT_IO_OPT_OMTU: opts->omtu = va_arg(args, int); if (!opts->mtu) opts->mtu = opts->omtu; break; case BT_IO_OPT_IMTU: opts->imtu = va_arg(args, int); if (!opts->mtu) opts->mtu = opts->imtu; break; case BT_IO_OPT_MASTER: opts->master = va_arg(args, gboolean); break; case BT_IO_OPT_MODE: opts->mode = va_arg(args, int); break; case BT_IO_OPT_FLUSHABLE: opts->flushable = va_arg(args, gboolean); break; case BT_IO_OPT_PRIORITY: opts->priority = va_arg(args, int); break; default: g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Unknown option %d", opt); return FALSE; } opt = va_arg(args, int); } return TRUE; } static gboolean get_peers(int sock, struct sockaddr *src, struct sockaddr *dst, socklen_t len, GError **err) { socklen_t olen; memset(src, 0, len); olen = len; if (getsockname(sock, src, &olen) < 0) { ERROR_FAILED(err, "getsockname", errno); return FALSE; } memset(dst, 0, len); olen = len; if (getpeername(sock, dst, &olen) < 0) { ERROR_FAILED(err, "getpeername", errno); return FALSE; } return TRUE; } static int l2cap_get_info(int sock, uint16_t *handle, uint8_t *dev_class) { struct l2cap_conninfo info; socklen_t len; len = sizeof(info); if (getsockopt(sock, SOL_L2CAP, L2CAP_CONNINFO, &info, &len) < 0) return -errno; if (handle) *handle = info.hci_handle; if (dev_class) memcpy(dev_class, info.dev_class, 3); return 0; } static int l2cap_get_flushable(int sock, gboolean *flushable) { int f; socklen_t len; f = 0; len = sizeof(f); if (getsockopt(sock, SOL_BLUETOOTH, BT_FLUSHABLE, &f, &len) < 0) return -errno; if (f) *flushable = TRUE; else *flushable = FALSE; return 0; } static int get_priority(int sock, uint32_t *prio) { socklen_t len; len = sizeof(*prio); if (getsockopt(sock, SOL_SOCKET, SO_PRIORITY, prio, &len) < 0) return -errno; return 0; } static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1, va_list args) { BtIOOption opt = opt1; struct sockaddr_l2 src, dst; struct l2cap_options l2o; int flags; uint8_t dev_class[3]; uint16_t handle; socklen_t len; gboolean flushable = FALSE; uint32_t priority; len = sizeof(l2o); memset(&l2o, 0, len); if (getsockopt(sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0) { ERROR_FAILED(err, "getsockopt(L2CAP_OPTIONS)", errno); return FALSE; } if (!get_peers(sock, (struct sockaddr *) &src, (struct sockaddr *) &dst, sizeof(src), err)) return FALSE; while (opt != BT_IO_OPT_INVALID) { switch (opt) { case BT_IO_OPT_SOURCE: ba2str(&src.l2_bdaddr, va_arg(args, char *)); break; case BT_IO_OPT_SOURCE_BDADDR: bacpy(va_arg(args, bdaddr_t *), &src.l2_bdaddr); break; case BT_IO_OPT_DEST: ba2str(&dst.l2_bdaddr, va_arg(args, char *)); break; case BT_IO_OPT_DEST_BDADDR: bacpy(va_arg(args, bdaddr_t *), &dst.l2_bdaddr); break; case BT_IO_OPT_DEST_TYPE: g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Not implemented"); return FALSE; case BT_IO_OPT_DEFER_TIMEOUT: len = sizeof(int); if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, va_arg(args, int *), &len) < 0) { ERROR_FAILED(err, "getsockopt(DEFER_SETUP)", errno); return FALSE; } break; case BT_IO_OPT_SEC_LEVEL: if (!get_sec_level(sock, BT_IO_L2CAP, va_arg(args, int *), err)) return FALSE; break; case BT_IO_OPT_KEY_SIZE: if (!get_key_size(sock, va_arg(args, int *), err)) return FALSE; break; case BT_IO_OPT_PSM: *(va_arg(args, uint16_t *)) = src.l2_psm ? btohs(src.l2_psm) : btohs(dst.l2_psm); break; case BT_IO_OPT_CID: *(va_arg(args, uint16_t *)) = src.l2_cid ? btohs(src.l2_cid) : btohs(dst.l2_cid); break; case BT_IO_OPT_OMTU: *(va_arg(args, uint16_t *)) = l2o.omtu; break; case BT_IO_OPT_IMTU: *(va_arg(args, uint16_t *)) = l2o.imtu; break; case BT_IO_OPT_MASTER: len = sizeof(flags); if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len) < 0) { ERROR_FAILED(err, "getsockopt(L2CAP_LM)", errno); return FALSE; } *(va_arg(args, gboolean *)) = (flags & L2CAP_LM_MASTER) ? TRUE : FALSE; break; case BT_IO_OPT_HANDLE: if (l2cap_get_info(sock, &handle, dev_class) < 0) { ERROR_FAILED(err, "L2CAP_CONNINFO", errno); return FALSE; } *(va_arg(args, uint16_t *)) = handle; break; case BT_IO_OPT_CLASS: if (l2cap_get_info(sock, &handle, dev_class) < 0) { ERROR_FAILED(err, "L2CAP_CONNINFO", errno); return FALSE; } memcpy(va_arg(args, uint8_t *), dev_class, 3); break; case BT_IO_OPT_MODE: *(va_arg(args, uint8_t *)) = l2o.mode; break; case BT_IO_OPT_FLUSHABLE: if (l2cap_get_flushable(sock, &flushable) < 0) { ERROR_FAILED(err, "get_flushable", errno); return FALSE; } *(va_arg(args, gboolean *)) = flushable; break; case BT_IO_OPT_PRIORITY: if (get_priority(sock, &priority) < 0) { ERROR_FAILED(err, "get_priority", errno); return FALSE; } *(va_arg(args, uint32_t *)) = priority; break; default: g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Unknown option %d", opt); return FALSE; } opt = va_arg(args, int); } return TRUE; } static int rfcomm_get_info(int sock, uint16_t *handle, uint8_t *dev_class) { struct rfcomm_conninfo info; socklen_t len; len = sizeof(info); if (getsockopt(sock, SOL_RFCOMM, RFCOMM_CONNINFO, &info, &len) < 0) return -errno; if (handle) *handle = info.hci_handle; if (dev_class) memcpy(dev_class, info.dev_class, 3); return 0; } static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1, va_list args) { BtIOOption opt = opt1; struct sockaddr_rc src, dst; int flags; socklen_t len; uint8_t dev_class[3]; uint16_t handle; if (!get_peers(sock, (struct sockaddr *) &src, (struct sockaddr *) &dst, sizeof(src), err)) return FALSE; while (opt != BT_IO_OPT_INVALID) { switch (opt) { case BT_IO_OPT_SOURCE: ba2str(&src.rc_bdaddr, va_arg(args, char *)); break; case BT_IO_OPT_SOURCE_BDADDR: bacpy(va_arg(args, bdaddr_t *), &src.rc_bdaddr); break; case BT_IO_OPT_DEST: ba2str(&dst.rc_bdaddr, va_arg(args, char *)); break; case BT_IO_OPT_DEST_BDADDR: bacpy(va_arg(args, bdaddr_t *), &dst.rc_bdaddr); break; case BT_IO_OPT_DEFER_TIMEOUT: len = sizeof(int); if (getsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, va_arg(args, int *), &len) < 0) { ERROR_FAILED(err, "getsockopt(DEFER_SETUP)", errno); return FALSE; } break; case BT_IO_OPT_SEC_LEVEL: if (!get_sec_level(sock, BT_IO_RFCOMM, va_arg(args, int *), err)) return FALSE; break; case BT_IO_OPT_CHANNEL: *(va_arg(args, uint8_t *)) = src.rc_channel ? src.rc_channel : dst.rc_channel; break; case BT_IO_OPT_SOURCE_CHANNEL: *(va_arg(args, uint8_t *)) = src.rc_channel; break; case BT_IO_OPT_DEST_CHANNEL: *(va_arg(args, uint8_t *)) = dst.rc_channel; break; case BT_IO_OPT_MASTER: len = sizeof(flags); if (getsockopt(sock, SOL_RFCOMM, RFCOMM_LM, &flags, &len) < 0) { ERROR_FAILED(err, "getsockopt(RFCOMM_LM)", errno); return FALSE; } *(va_arg(args, gboolean *)) = (flags & RFCOMM_LM_MASTER) ? TRUE : FALSE; break; case BT_IO_OPT_HANDLE: if (rfcomm_get_info(sock, &handle, dev_class) < 0) { ERROR_FAILED(err, "RFCOMM_CONNINFO", errno); return FALSE; } *(va_arg(args, uint16_t *)) = handle; break; case BT_IO_OPT_CLASS: if (rfcomm_get_info(sock, &handle, dev_class) < 0) { ERROR_FAILED(err, "RFCOMM_CONNINFO", errno); return FALSE; } memcpy(va_arg(args, uint8_t *), dev_class, 3); break; default: g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Unknown option %d", opt); return FALSE; } opt = va_arg(args, int); } return TRUE; } static int sco_get_info(int sock, uint16_t *handle, uint8_t *dev_class) { struct sco_conninfo info; socklen_t len; len = sizeof(info); if (getsockopt(sock, SOL_SCO, SCO_CONNINFO, &info, &len) < 0) return -errno; if (handle) *handle = info.hci_handle; if (dev_class) memcpy(dev_class, info.dev_class, 3); return 0; } static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args) { BtIOOption opt = opt1; struct sockaddr_sco src, dst; struct sco_options sco_opt; socklen_t len; uint8_t dev_class[3]; uint16_t handle; len = sizeof(sco_opt); memset(&sco_opt, 0, len); if (getsockopt(sock, SOL_SCO, SCO_OPTIONS, &sco_opt, &len) < 0) { ERROR_FAILED(err, "getsockopt(SCO_OPTIONS)", errno); return FALSE; } if (!get_peers(sock, (struct sockaddr *) &src, (struct sockaddr *) &dst, sizeof(src), err)) return FALSE; while (opt != BT_IO_OPT_INVALID) { switch (opt) { case BT_IO_OPT_SOURCE: ba2str(&src.sco_bdaddr, va_arg(args, char *)); break; case BT_IO_OPT_SOURCE_BDADDR: bacpy(va_arg(args, bdaddr_t *), &src.sco_bdaddr); break; case BT_IO_OPT_DEST: ba2str(&dst.sco_bdaddr, va_arg(args, char *)); break; case BT_IO_OPT_DEST_BDADDR: bacpy(va_arg(args, bdaddr_t *), &dst.sco_bdaddr); break; case BT_IO_OPT_MTU: case BT_IO_OPT_IMTU: case BT_IO_OPT_OMTU: *(va_arg(args, uint16_t *)) = sco_opt.mtu; break; case BT_IO_OPT_HANDLE: if (sco_get_info(sock, &handle, dev_class) < 0) { ERROR_FAILED(err, "SCO_CONNINFO", errno); return FALSE; } *(va_arg(args, uint16_t *)) = handle; break; case BT_IO_OPT_CLASS: if (sco_get_info(sock, &handle, dev_class) < 0) { ERROR_FAILED(err, "SCO_CONNINFO", errno); return FALSE; } memcpy(va_arg(args, uint8_t *), dev_class, 3); break; default: g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Unknown option %d", opt); return FALSE; } opt = va_arg(args, int); } return TRUE; } static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err, BtIOOption opt1, va_list args) { int sock; sock = g_io_channel_unix_get_fd(io); switch (type) { case BT_IO_L2RAW: case BT_IO_L2CAP: case BT_IO_L2ERTM: return l2cap_get(sock, err, opt1, args); case BT_IO_RFCOMM: return rfcomm_get(sock, err, opt1, args); case BT_IO_SCO: return sco_get(sock, err, opt1, args); } g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Unknown BtIO type %d", type); return FALSE; } gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data, GDestroyNotify destroy, GError **err) { int sock; char c; struct pollfd pfd; sock = g_io_channel_unix_get_fd(io); memset(&pfd, 0, sizeof(pfd)); pfd.fd = sock; pfd.events = POLLOUT; if (poll(&pfd, 1, 0) < 0) { ERROR_FAILED(err, "poll", errno); return FALSE; } if (!(pfd.revents & POLLOUT)) { if (read(sock, &c, 1) < 0) { ERROR_FAILED(err, "read", errno); return FALSE; } } accept_add(io, connect, user_data, destroy); return TRUE; } gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err, BtIOOption opt1, ...) { va_list args; gboolean ret; struct set_opts opts; int sock; va_start(args, opt1); ret = parse_set_opts(&opts, err, opt1, args); va_end(args); if (!ret) return ret; sock = g_io_channel_unix_get_fd(io); switch (type) { case BT_IO_L2RAW: case BT_IO_L2CAP: case BT_IO_L2ERTM: return l2cap_set(sock, opts.sec_level, opts.imtu, opts.omtu, opts.mode, opts.master, opts.flushable, opts.priority, err); case BT_IO_RFCOMM: return rfcomm_set(sock, opts.sec_level, opts.master, err); case BT_IO_SCO: return sco_set(sock, opts.mtu, err); } g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Unknown BtIO type %d", type); return FALSE; } gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err, BtIOOption opt1, ...) { va_list args; gboolean ret; va_start(args, opt1); ret = get_valist(io, type, err, opt1, args); va_end(args); return ret; } static GIOChannel *create_io(BtIOType type, gboolean server, struct set_opts *opts, GError **err) { int sock; GIOChannel *io; switch (type) { case BT_IO_L2RAW: sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP); if (sock < 0) { ERROR_FAILED(err, "socket(RAW, L2CAP)", errno); return NULL; } if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0, opts->cid, err) < 0) goto failed; if (!l2cap_set(sock, opts->sec_level, 0, 0, 0, -1, -1, 0, err)) goto failed; break; case BT_IO_L2CAP: sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (sock < 0) { ERROR_FAILED(err, "socket(SEQPACKET, L2CAP)", errno); return NULL; } if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0, opts->cid, err) < 0) goto failed; if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu, opts->mode, opts->master, opts->flushable, opts->priority, err)) goto failed; break; case BT_IO_L2ERTM: sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_L2CAP); if (sock < 0) { ERROR_FAILED(err, "socket(STREAM, L2CAP)", errno); return NULL; } if (l2cap_bind(sock, &opts->src, server ? opts->psm : 0, opts->cid, err) < 0) goto failed; if (!l2cap_set(sock, opts->sec_level, opts->imtu, opts->omtu, opts->mode, opts->master, opts->flushable, opts->priority, err)) goto failed; break; case BT_IO_RFCOMM: sock = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sock < 0) { ERROR_FAILED(err, "socket(STREAM, RFCOMM)", errno); return NULL; } if (rfcomm_bind(sock, &opts->src, server ? opts->channel : 0, err) < 0) goto failed; if (!rfcomm_set(sock, opts->sec_level, opts->master, err)) goto failed; break; case BT_IO_SCO: sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO); if (sock < 0) { ERROR_FAILED(err, "socket(SEQPACKET, SCO)", errno); return NULL; } if (sco_bind(sock, &opts->src, err) < 0) goto failed; if (!sco_set(sock, opts->mtu, err)) goto failed; break; default: g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Unknown BtIO type %d", type); return NULL; } io = g_io_channel_unix_new(sock); g_io_channel_set_close_on_unref(io, TRUE); g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL); return io; failed: close(sock); return NULL; } GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect, gpointer user_data, GDestroyNotify destroy, GError **gerr, BtIOOption opt1, ...) { GIOChannel *io; va_list args; struct set_opts opts; int err, sock; gboolean ret; va_start(args, opt1); ret = parse_set_opts(&opts, gerr, opt1, args); va_end(args); if (ret == FALSE) return NULL; io = create_io(type, FALSE, &opts, gerr); if (io == NULL) return NULL; sock = g_io_channel_unix_get_fd(io); switch (type) { case BT_IO_L2RAW: err = l2cap_connect(sock, &opts.dst, opts.dst_type, 0, opts.cid); break; case BT_IO_L2CAP: case BT_IO_L2ERTM: err = l2cap_connect(sock, &opts.dst, opts.dst_type, opts.psm, opts.cid); break; case BT_IO_RFCOMM: err = rfcomm_connect(sock, &opts.dst, opts.channel); break; case BT_IO_SCO: err = sco_connect(sock, &opts.dst); break; default: g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Unknown BtIO type %d", type); return NULL; } if (err < 0) { g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED, "connect: %s (%d)", strerror(-err), -err); g_io_channel_unref(io); return NULL; } connect_add(io, connect, user_data, destroy); return io; } GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect, BtIOConfirm confirm, gpointer user_data, GDestroyNotify destroy, GError **err, BtIOOption opt1, ...) { GIOChannel *io; va_list args; struct set_opts opts; int sock; gboolean ret; if (type == BT_IO_L2RAW) { g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS, "Server L2CAP RAW sockets not supported"); return NULL; } va_start(args, opt1); ret = parse_set_opts(&opts, err, opt1, args); va_end(args); if (ret == FALSE) return NULL; io = create_io(type, TRUE, &opts, err); if (io == NULL) return NULL; sock = g_io_channel_unix_get_fd(io); if (confirm) setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer, sizeof(opts.defer)); if (listen(sock, 5) < 0) { ERROR_FAILED(err, "listen", errno); g_io_channel_unref(io); return NULL; } server_add(io, connect, confirm, user_data, destroy); return io; } GQuark bt_io_error_quark(void) { return g_quark_from_static_string("bt-io-error-quark"); } bluez-4.101/btio/btio.h0000644000000000000000000000535311766125764011617 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2009-2010 Marcel Holtmann * Copyright (C) 2009-2010 Nokia Corporation * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef BT_IO_H #define BT_IO_H #include typedef enum { BT_IO_ERROR_DISCONNECTED, BT_IO_ERROR_CONNECT_FAILED, BT_IO_ERROR_FAILED, BT_IO_ERROR_INVALID_ARGS, } BtIOError; #define BT_IO_ERROR bt_io_error_quark() GQuark bt_io_error_quark(void); typedef enum { BT_IO_L2RAW, BT_IO_L2CAP, BT_IO_L2ERTM, BT_IO_RFCOMM, BT_IO_SCO, } BtIOType; typedef enum { BT_IO_OPT_INVALID = 0, BT_IO_OPT_SOURCE, BT_IO_OPT_SOURCE_BDADDR, BT_IO_OPT_DEST, BT_IO_OPT_DEST_BDADDR, BT_IO_OPT_DEST_TYPE, BT_IO_OPT_DEFER_TIMEOUT, BT_IO_OPT_SEC_LEVEL, BT_IO_OPT_KEY_SIZE, BT_IO_OPT_CHANNEL, BT_IO_OPT_SOURCE_CHANNEL, BT_IO_OPT_DEST_CHANNEL, BT_IO_OPT_PSM, BT_IO_OPT_CID, BT_IO_OPT_MTU, BT_IO_OPT_OMTU, BT_IO_OPT_IMTU, BT_IO_OPT_MASTER, BT_IO_OPT_HANDLE, BT_IO_OPT_CLASS, BT_IO_OPT_MODE, BT_IO_OPT_FLUSHABLE, BT_IO_OPT_PRIORITY, } BtIOOption; typedef enum { BT_IO_SEC_SDP = 0, BT_IO_SEC_LOW, BT_IO_SEC_MEDIUM, BT_IO_SEC_HIGH, } BtIOSecLevel; typedef enum { BT_IO_MODE_BASIC = 0, BT_IO_MODE_RETRANS, BT_IO_MODE_FLOWCTL, BT_IO_MODE_ERTM, BT_IO_MODE_STREAMING } BtIOMode; typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data); typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data); gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data, GDestroyNotify destroy, GError **err); gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err, BtIOOption opt1, ...); gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err, BtIOOption opt1, ...); GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect, gpointer user_data, GDestroyNotify destroy, GError **err, BtIOOption opt1, ...); GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect, BtIOConfirm confirm, gpointer user_data, GDestroyNotify destroy, GError **err, BtIOOption opt1, ...); #endif bluez-4.101/mgmt/0000755000000000000000000000000011771120004010544 500000000000000bluez-4.101/mgmt/main.c0000644000000000000000000012773211766125764011616 00000000000000/* * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Intel Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "glib-helper.h" static bool monitor = false; static bool discovery = false; static bool resolve_names = true; typedef void (*cmd_cb)(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data); static struct pending_cmd { uint16_t op; uint16_t id; cmd_cb cb; void *user_data; struct pending_cmd *next; } *pending = NULL; static int mgmt_send_cmd(int mgmt_sk, uint16_t op, uint16_t id, void *data, size_t len, cmd_cb func, void *user_data) { char buf[1024]; struct pending_cmd *cmd; struct mgmt_hdr *hdr = (void *) buf; if (len + MGMT_HDR_SIZE > sizeof(buf)) return -EINVAL; cmd = calloc(1, sizeof(struct pending_cmd)); if (cmd == NULL) return -errno; cmd->op = op; cmd->id = id; cmd->cb = func; cmd->user_data = user_data; memset(buf, 0, sizeof(buf)); hdr->opcode = htobs(op); hdr->index = htobs(id); hdr->len = htobs(len); memcpy(buf + MGMT_HDR_SIZE, data, len); if (write(mgmt_sk, buf, MGMT_HDR_SIZE + len) < 0) { fprintf(stderr, "Unable to write to socket: %s\n", strerror(errno)); free(cmd); return -1; } cmd->next = pending; pending = cmd; return 0; } static int mgmt_open(void) { struct sockaddr_hci addr; int sk; sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI); if (sk < 0) { fprintf(stderr, "socket: %s\n", strerror(errno)); return sk; } memset(&addr, 0, sizeof(addr)); addr.hci_family = AF_BLUETOOTH; addr.hci_dev = HCI_DEV_NONE; addr.hci_channel = HCI_CHANNEL_CONTROL; if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { fprintf(stderr, "bind: %s\n", strerror(errno)); close(sk); return -1; } return sk; } static void mgmt_check_pending(int mgmt_sk, uint16_t op, uint16_t index, uint16_t status, void *data, uint16_t len) { struct pending_cmd *c, *prev; for (c = pending, prev = NULL; c != NULL; prev = c, c = c->next) { if (c->op != op) continue; if (c->id != index) continue; if (c == pending) pending = c->next; else prev->next = c->next; c->cb(mgmt_sk, op, index, status, data, len, c->user_data); free(c); break; } } static int mgmt_cmd_complete(int mgmt_sk, uint16_t index, struct mgmt_ev_cmd_complete *ev, uint16_t len) { uint16_t op; if (len < sizeof(*ev)) { fprintf(stderr, "Too short (%u bytes) cmd complete event\n", len); return -EINVAL; } op = bt_get_le16(&ev->opcode); len -= sizeof(*ev); if (monitor) printf("%s complete, opcode 0x%04x len %u\n", mgmt_opstr(op), op, len); mgmt_check_pending(mgmt_sk, op, index, ev->status, ev->data, len); return 0; } static int mgmt_cmd_status(int mgmt_sk, uint16_t index, struct mgmt_ev_cmd_status *ev, uint16_t len) { uint16_t opcode; if (len < sizeof(*ev)) { fprintf(stderr, "Too short (%u bytes) cmd status event\n", len); return -EINVAL; } opcode = bt_get_le16(&ev->opcode); if (monitor) printf("cmd status, opcode 0x%04x status 0x%02x (%s)\n", opcode, ev->status, mgmt_errstr(ev->status)); if (ev->status != 0) mgmt_check_pending(mgmt_sk, opcode, index, ev->status, NULL, 0); return 0; } static int mgmt_controller_error(uint16_t index, struct mgmt_ev_controller_error *ev, uint16_t len) { if (len < sizeof(*ev)) { fprintf(stderr, "Too short (%u bytes) controller error event\n", len); return -EINVAL; } if (monitor) printf("hci%u error 0x%02x\n", index, ev->error_code); return 0; } static int mgmt_index_added(int mgmt_sk, uint16_t index) { if (monitor) printf("hci%u added\n", index); return 0; } static int mgmt_index_removed(int mgmt_sk, uint16_t index) { if (monitor) printf("hci%u removed\n", index); return 0; } static const char *settings_str[] = { "powered", "connectable", "fast-connectable", "discoverable", "pairable", "link-security", "ssp", "br/edr", "hs", "le" , }; static void print_settings(uint32_t settings) { unsigned i; for (i = 0; i < NELEM(settings_str); i++) { if ((settings & (1 << i)) != 0) printf("%s ", settings_str[i]); } } static int mgmt_new_settings(int mgmt_sk, uint16_t index, uint32_t *ev, uint16_t len) { if (len < sizeof(*ev)) { fprintf(stderr, "Too short new_settings event (%u)\n", len); return -EINVAL; } if (monitor) { printf("hci%u new_settings: ", index); print_settings(bt_get_le32(ev)); printf("\n"); } return 0; } static int mgmt_discovering(int mgmt_sk, uint16_t index, struct mgmt_ev_discovering *ev, uint16_t len) { if (len < sizeof(*ev)) { fprintf(stderr, "Too short (%u bytes) discovering event\n", len); return -EINVAL; } if (ev->discovering == 0 && discovery) exit(EXIT_SUCCESS); if (monitor) printf("hci%u type %u discovering %s\n", index, ev->type, ev->discovering ? "on" : "off"); return 0; } static int mgmt_new_link_key(int mgmt_sk, uint16_t index, struct mgmt_ev_new_link_key *ev, uint16_t len) { if (len != sizeof(*ev)) { fprintf(stderr, "Invalid new_link_key length (%u bytes)\n", len); return -EINVAL; } if (monitor) { char addr[18]; ba2str(&ev->key.addr.bdaddr, addr); printf("hci%u new_link_key %s type 0x%02x pin_len %d " "store_hint %u\n", index, addr, ev->key.type, ev->key.pin_len, ev->store_hint); } return 0; } static const char *typestr(uint8_t type) { const char *str[] = { "BR/EDR", "LE Public", "LE Random" }; if (type <= BDADDR_LE_RANDOM) return str[type]; return "(unknown)"; } static int mgmt_connected(int mgmt_sk, uint16_t index, struct mgmt_ev_device_connected *ev, uint16_t len) { uint16_t eir_len; if (len < sizeof(*ev)) { fprintf(stderr, "Invalid connected event length (%u bytes)\n", len); return -EINVAL; } eir_len = bt_get_le16(&ev->eir_len); if (len != sizeof(*ev) + eir_len) { fprintf(stderr, "Invalid connected event length " "(%u bytes, eir_len %u bytes)\n", len, eir_len); return -EINVAL; } if (monitor) { char addr[18]; ba2str(&ev->addr.bdaddr, addr); printf("hci%u %s type %s connected eir_len %u\n", index, addr, typestr(ev->addr.type), eir_len); } return 0; } static int mgmt_disconnected(int mgmt_sk, uint16_t index, struct mgmt_addr_info *ev, uint16_t len) { if (len != sizeof(*ev)) { fprintf(stderr, "Invalid disconnected event length (%u bytes)\n", len); return -EINVAL; } if (monitor) { char addr[18]; ba2str(&ev->bdaddr, addr); printf("hci%u %s type %s disconnected\n", index, addr, typestr(ev->type)); } return 0; } static int mgmt_conn_failed(int mgmt_sk, uint16_t index, struct mgmt_ev_connect_failed *ev, uint16_t len) { if (len != sizeof(*ev)) { fprintf(stderr, "Invalid connect_failed event length (%u bytes)\n", len); return -EINVAL; } if (monitor) { char addr[18]; ba2str(&ev->addr.bdaddr, addr); printf("hci%u %s type %s connect failed (status 0x%02x, %s)\n", index, addr, typestr(ev->addr.type), ev->status, mgmt_errstr(ev->status)); } return 0; } static int mgmt_auth_failed(int mgmt_sk, uint16_t index, struct mgmt_ev_auth_failed *ev, uint16_t len) { if (len != sizeof(*ev)) { fprintf(stderr, "Invalid auth_failed event length (%u bytes)\n", len); return -EINVAL; } if (monitor) { char addr[18]; ba2str(&ev->addr.bdaddr, addr); printf("hci%u %s auth failed with status 0x%02x (%s)\n", index, addr, ev->status, mgmt_errstr(ev->status)); } return 0; } static int mgmt_name_changed(int mgmt_sk, uint16_t index, struct mgmt_ev_local_name_changed *ev, uint16_t len) { if (len != sizeof(*ev)) { fprintf(stderr, "Invalid local_name_changed length (%u bytes)\n", len); return -EINVAL; } if (monitor) printf("hci%u name changed: %s\n", index, ev->name); return 0; } static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_confirm_name *rp = rsp; char addr[18]; if (len == 0 && status != 0) { fprintf(stderr, "hci%u confirm_name failed with status 0x%02x (%s)\n", id, status, mgmt_errstr(status)); return; } if (len != sizeof(*rp)) { fprintf(stderr, "hci%u confirm_name rsp length %u instead of %zu\n", id, len, sizeof(*rp)); return; } ba2str(&rp->addr.bdaddr, addr); if (status != 0) fprintf(stderr, "hci%u confirm_name for %s failed: 0x%02x (%s)\n", id, addr, status, mgmt_errstr(status)); else printf("hci%u confirm_name succeeded for %s\n", id, addr); } static int mgmt_device_found(int mgmt_sk, uint16_t index, struct mgmt_ev_device_found *ev, uint16_t len) { uint32_t flags; uint16_t eir_len; if (len < sizeof(*ev)) { fprintf(stderr, "Too short device_found length (%u bytes)\n", len); return -EINVAL; } flags = btohs(ev->flags); eir_len = bt_get_le16(&ev->eir_len); if (len != sizeof(*ev) + eir_len) { fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes", sizeof(*ev) + eir_len, len); return -EINVAL; } if (monitor || discovery) { char addr[18]; ba2str(&ev->addr.bdaddr, addr); printf("hci%u dev_found: %s type %s rssi %d " "flags 0x%04x eir_len %u\n", index, addr, typestr(ev->addr.type), ev->rssi, flags, eir_len); } if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) { struct mgmt_cp_confirm_name cp; memset(&cp, 0, sizeof(cp)); memcpy(&cp.addr, &ev->addr, sizeof(cp.addr)); if (resolve_names) cp.name_known = 0; else cp.name_known = 1; mgmt_send_cmd(mgmt_sk, MGMT_OP_CONFIRM_NAME, index, &cp, sizeof(cp), confirm_name_rsp, NULL); } return 0; } static void pin_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { if (status != 0) { fprintf(stderr, "hci%u PIN Code reply failed with status 0x%02x (%s)", id, status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("hci%u PIN Reply successful\n", id); } static int mgmt_pin_reply(int mgmt_sk, uint16_t index, struct mgmt_addr_info *addr, const char *pin, size_t len) { struct mgmt_cp_pin_code_reply cp; memset(&cp, 0, sizeof(cp)); memcpy(&cp.addr, addr, sizeof(cp.addr)); cp.pin_len = len; memcpy(cp.pin_code, pin, len); return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_REPLY, index, &cp, sizeof(cp), pin_rsp, NULL); } static void pin_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { if (status != 0) { fprintf(stderr, "hci%u PIN Neg reply failed with status 0x%02x (%s)", id, status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("hci%u PIN Negative Reply successful\n", id); } static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index, struct mgmt_addr_info *addr) { struct mgmt_cp_pin_code_neg_reply cp; memset(&cp, 0, sizeof(cp)); memcpy(&cp.addr, addr, sizeof(cp.addr)); return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, &cp, sizeof(cp), pin_neg_rsp, NULL); } static int mgmt_request_pin(int mgmt_sk, uint16_t index, struct mgmt_ev_pin_code_request *ev, uint16_t len) { char pin[18]; size_t pin_len; if (len != sizeof(*ev)) { fprintf(stderr, "Invalid pin_code request length (%u bytes)\n", len); return -EINVAL; } if (monitor) { char addr[18]; ba2str(&ev->addr.bdaddr, addr); printf("hci%u %s request PIN\n", index, addr); } printf("PIN Request (press enter to reject) >> "); fflush(stdout); memset(pin, 0, sizeof(pin)); if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n') return mgmt_pin_neg_reply(mgmt_sk, index, &ev->addr); pin_len = strlen(pin); if (pin[pin_len - 1] == '\n') { pin[pin_len - 1] = '\0'; pin_len--; } return mgmt_pin_reply(mgmt_sk, index, &ev->addr, pin, pin_len); } static void confirm_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { if (status != 0) { fprintf(stderr, "hci%u User Confirm reply failed. status 0x%02x (%s)", id, status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("hci%u User Confirm Reply successful\n", id); } static int mgmt_confirm_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr) { struct mgmt_cp_user_confirm_reply cp; memset(&cp, 0, sizeof(cp)); bacpy(&cp.addr.bdaddr, bdaddr); return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_REPLY, index, &cp, sizeof(cp), confirm_rsp, NULL); } static void confirm_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { if (status != 0) { fprintf(stderr, "hci%u Confirm Neg reply failed. status 0x%02x (%s)", id, status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("hci%u User Confirm Negative Reply successful\n", id); } static int mgmt_confirm_neg_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr) { struct mgmt_cp_user_confirm_reply cp; memset(&cp, 0, sizeof(cp)); bacpy(&cp.addr.bdaddr, bdaddr); return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_NEG_REPLY, index, &cp, sizeof(cp), confirm_neg_rsp, NULL); } static int mgmt_user_confirm(int mgmt_sk, uint16_t index, struct mgmt_ev_user_confirm_request *ev, uint16_t len) { char rsp[5]; size_t rsp_len; uint32_t val; char addr[18]; if (len != sizeof(*ev)) { fprintf(stderr, "Invalid user_confirm request length (%u)\n", len); return -EINVAL; } ba2str(&ev->addr.bdaddr, addr); val = bt_get_le32(&ev->value); if (monitor) printf("hci%u %s User Confirm %06u hint %u\n", index, addr, val, ev->confirm_hint); if (ev->confirm_hint) printf("Accept pairing with %s (yes/no) >> ", addr); else printf("Confirm value %06u for %s (yes/no) >> ", val, addr); fflush(stdout); memset(rsp, 0, sizeof(rsp)); if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n') return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr); rsp_len = strlen(rsp); if (rsp[rsp_len - 1] == '\n') { rsp[rsp_len - 1] = '\0'; rsp_len--; } if (rsp[0] == 'y' || rsp[0] == 'Y') return mgmt_confirm_reply(mgmt_sk, index, &ev->addr.bdaddr); else return mgmt_confirm_neg_reply(mgmt_sk, index, &ev->addr.bdaddr); } static int mgmt_handle_event(int mgmt_sk, uint16_t ev, uint16_t index, void *data, uint16_t len) { if (monitor) printf("event: %s\n", mgmt_evstr(ev)); switch (ev) { case MGMT_EV_CMD_COMPLETE: return mgmt_cmd_complete(mgmt_sk, index, data, len); case MGMT_EV_CMD_STATUS: return mgmt_cmd_status(mgmt_sk, index, data, len); case MGMT_EV_CONTROLLER_ERROR: return mgmt_controller_error(index, data, len); case MGMT_EV_INDEX_ADDED: return mgmt_index_added(mgmt_sk, index); case MGMT_EV_INDEX_REMOVED: return mgmt_index_removed(mgmt_sk, index); case MGMT_EV_NEW_SETTINGS: return mgmt_new_settings(mgmt_sk, index, data, len); case MGMT_EV_DISCOVERING: return mgmt_discovering(mgmt_sk, index, data, len); case MGMT_EV_NEW_LINK_KEY: return mgmt_new_link_key(mgmt_sk, index, data, len); case MGMT_EV_DEVICE_CONNECTED: return mgmt_connected(mgmt_sk, index, data, len); case MGMT_EV_DEVICE_DISCONNECTED: return mgmt_disconnected(mgmt_sk, index, data, len); case MGMT_EV_CONNECT_FAILED: return mgmt_conn_failed(mgmt_sk, index, data, len); case MGMT_EV_AUTH_FAILED: return mgmt_auth_failed(mgmt_sk, index, data, len); case MGMT_EV_LOCAL_NAME_CHANGED: return mgmt_name_changed(mgmt_sk, index, data, len); case MGMT_EV_DEVICE_FOUND: return mgmt_device_found(mgmt_sk, index, data, len); case MGMT_EV_PIN_CODE_REQUEST: return mgmt_request_pin(mgmt_sk, index, data, len); case MGMT_EV_USER_CONFIRM_REQUEST: return mgmt_user_confirm(mgmt_sk, index, data, len); default: if (monitor) printf("Unhandled event 0x%04x (%s)\n", ev, mgmt_evstr(ev)); return 0; } } static int mgmt_process_data(int mgmt_sk) { char buf[1024]; struct mgmt_hdr *hdr = (void *) buf; uint16_t len, ev, index; ssize_t ret; ret = read(mgmt_sk, buf, sizeof(buf)); if (ret < 0) { fprintf(stderr, "read: %s\n", strerror(errno)); return ret; } if (ret < MGMT_HDR_SIZE) { fprintf(stderr, "Too small mgmt packet (%zd bytes)\n", ret); return 0; } ev = bt_get_le16(&hdr->opcode); index = bt_get_le16(&hdr->index); len = bt_get_le16(&hdr->len); if (monitor) printf("event 0x%04x len 0x%04x index 0x%04x\n", ev, len, index); if (ret != MGMT_HDR_SIZE + len) { fprintf(stderr, "Packet length mismatch. ret %zd len %u", ret, len); return 0; } mgmt_handle_event(mgmt_sk, ev, index, buf + MGMT_HDR_SIZE, len); return 0; } static void cmd_monitor(int mgmt_sk, uint16_t index, int argc, char **argv) { printf("Monitoring mgmt events...\n"); monitor = true; } static void version_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_read_version *rp = rsp; if (status != 0) { fprintf(stderr, "Reading mgmt version failed with status" " 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len < sizeof(*rp)) { fprintf(stderr, "Too small version reply (%u bytes)\n", len); exit(EXIT_FAILURE); } printf("MGMT Version %u, revision %u\n", rp->version, bt_get_le16(&rp->revision)); exit(EXIT_SUCCESS); } static void cmd_version(int mgmt_sk, uint16_t index, int argc, char **argv) { if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, NULL, 0, version_rsp, NULL) < 0) { fprintf(stderr, "Unable to send read_version cmd\n"); exit(EXIT_FAILURE); } } static void commands_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_read_commands *rp = rsp; uint16_t num_commands, num_events, *opcode; size_t expected_len; int i; if (status != 0) { fprintf(stderr, "Reading supported commands failed with status" " 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len < sizeof(*rp)) { fprintf(stderr, "Too small commands reply (%u bytes)\n", len); exit(EXIT_FAILURE); } num_commands = bt_get_le16(&rp->num_commands); num_events = bt_get_le16(&rp->num_events); expected_len = sizeof(*rp) + num_commands * sizeof(uint16_t) + num_events * sizeof(uint16_t); if (len < expected_len) { fprintf(stderr, "Too small commands reply (%u != %zu)\n", len, expected_len); exit(EXIT_FAILURE); } opcode = rp->opcodes; printf("%u commands:\n", num_commands); for (i = 0; i < num_commands; i++) { uint16_t op = bt_get_le16(opcode++); printf("\t%s (0x%04x)\n", mgmt_opstr(op), op); } printf("%u events:\n", num_events); for (i = 0; i < num_events; i++) { uint16_t ev = bt_get_le16(opcode++); printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev); } exit(EXIT_SUCCESS); } static void cmd_commands(int mgmt_sk, uint16_t index, int argc, char **argv) { if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, NULL, 0, commands_rsp, NULL) < 0) { fprintf(stderr, "Unable to send read_commands cmd\n"); exit(EXIT_FAILURE); } } static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_read_info *rp = rsp; char addr[18]; if (status != 0) { fprintf(stderr, "Reading hci%u info failed with status 0x%02x (%s)\n", id, status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len < sizeof(*rp)) { fprintf(stderr, "Too small info reply (%u bytes)\n", len); exit(EXIT_FAILURE); } ba2str(&rp->bdaddr, addr); printf("hci%u:\taddr %s version %u manufacturer %u" " class 0x%02x%02x%02x\n", id, addr, rp->version, bt_get_le16(&rp->manufacturer), rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]); printf("\tsupported settings: "); print_settings(bt_get_le32(&rp->supported_settings)); printf("\n\tcurrent settings: "); print_settings(bt_get_le32(&rp->current_settings)); printf("\n\tname %s\n", rp->name); printf("\tshort name %s\n", rp->short_name); if (pending == NULL) exit(EXIT_SUCCESS); } static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_read_index_list *rp = rsp; uint16_t count; unsigned int i; if (status != 0) { fprintf(stderr, "Reading index list failed with status 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len < sizeof(*rp)) { fprintf(stderr, "Too small index list reply (%u bytes)\n", len); exit(EXIT_FAILURE); } count = bt_get_le16(&rp->num_controllers); if (len < sizeof(*rp) + count * sizeof(uint16_t)) { fprintf(stderr, "Index count (%u) doesn't match reply length (%u)\n", count, len); exit(EXIT_FAILURE); } if (monitor) printf("Index list with %u item%s\n", count, count > 1 ? "s" : ""); if (count == 0) exit(EXIT_SUCCESS); if (monitor && count > 0) printf("\t"); for (i = 0; i < count; i++) { uint16_t index; index = bt_get_le16(&rp->index[i]); if (monitor) printf("hci%u ", index); if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL, 0, info_rsp, NULL) < 0) { fprintf(stderr, "Unable to send read_info cmd\n"); exit(EXIT_FAILURE); } } if (monitor && count > 0) printf("\n"); } static void cmd_info(int mgmt_sk, uint16_t index, int argc, char **argv) { if (index == MGMT_INDEX_NONE) { if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, NULL, 0, index_rsp, NULL) < 0) { fprintf(stderr, "Unable to send index_list cmd\n"); exit(EXIT_FAILURE); } return; } if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL, 0, info_rsp, NULL) < 0) { fprintf(stderr, "Unable to send read_info cmd\n"); exit(EXIT_FAILURE); } } static void setting_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { uint32_t *rp = rsp; if (status != 0) { fprintf(stderr, "%s for hci%u failed with status 0x%02x (%s)\n", mgmt_opstr(op), id, status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len < sizeof(*rp)) { fprintf(stderr, "Too small %s response (%u bytes)\n", mgmt_opstr(op), len); exit(EXIT_FAILURE); } printf("hci%u %s complete, settings: ", id, mgmt_opstr(op)); print_settings(bt_get_le32(rp)); printf("\n"); exit(EXIT_SUCCESS); } static void cmd_setting(int mgmt_sk, uint16_t index, uint16_t op, int argc, char **argv) { uint8_t val; if (argc < 2) { printf("Specify \"on\" or \"off\"\n"); exit(EXIT_FAILURE); } if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) val = 1; else if (strcasecmp(argv[1], "off") == 0) val = 0; else val = atoi(argv[1]); if (index == MGMT_INDEX_NONE) index = 0; if (mgmt_send_cmd(mgmt_sk, op, index, &val, sizeof(val), setting_rsp, NULL) < 0) { fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op)); exit(EXIT_FAILURE); } } static void cmd_power(int mgmt_sk, uint16_t index, int argc, char **argv) { cmd_setting(mgmt_sk, index, MGMT_OP_SET_POWERED, argc, argv); } static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_set_discoverable cp; if (argc < 2) { printf("Usage: btmgmt %s [timeout]\n", argv[0]); exit(EXIT_FAILURE); } memset(&cp, 0, sizeof(cp)); if (strcasecmp(argv[1], "on") == 0 || strcasecmp(argv[1], "yes") == 0) cp.val = 1; else if (strcasecmp(argv[1], "off") == 0) cp.val = 0; else cp.val = atoi(argv[1]); if (argc > 2) cp.timeout = htobs(atoi(argv[2])); if (index == MGMT_INDEX_NONE) index = 0; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DISCOVERABLE, index, &cp, sizeof(cp), setting_rsp, NULL) < 0) { fprintf(stderr, "Unable to send set_discoverable cmd\n"); exit(EXIT_FAILURE); } } static void cmd_connectable(int mgmt_sk, uint16_t index, int argc, char **argv) { cmd_setting(mgmt_sk, index, MGMT_OP_SET_CONNECTABLE, argc, argv); } static void cmd_pairable(int mgmt_sk, uint16_t index, int argc, char **argv) { cmd_setting(mgmt_sk, index, MGMT_OP_SET_PAIRABLE, argc, argv); } static void cmd_linksec(int mgmt_sk, uint16_t index, int argc, char **argv) { cmd_setting(mgmt_sk, index, MGMT_OP_SET_LINK_SECURITY, argc, argv); } static void cmd_ssp(int mgmt_sk, uint16_t index, int argc, char **argv) { cmd_setting(mgmt_sk, index, MGMT_OP_SET_SSP, argc, argv); } static void cmd_hs(int mgmt_sk, uint16_t index, int argc, char **argv) { cmd_setting(mgmt_sk, index, MGMT_OP_SET_HS, argc, argv); } static void cmd_le(int mgmt_sk, uint16_t index, int argc, char **argv) { cmd_setting(mgmt_sk, index, MGMT_OP_SET_LE, argc, argv); } static void class_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_ev_class_of_dev_changed *rp = rsp; if (len == 0 && status != 0) { fprintf(stderr, "%s failed, status 0x%02x (%s)\n", mgmt_opstr(op), status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len != sizeof(*rp)) { fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len); exit(EXIT_FAILURE); } printf("%s succeeded. Class 0x%02x%02x%02x\n", mgmt_opstr(op), rp->class_of_dev[2], rp->class_of_dev[1], rp->class_of_dev[0]); exit(EXIT_SUCCESS); } static void cmd_class(int mgmt_sk, uint16_t index, int argc, char **argv) { uint8_t class[2]; if (argc < 3) { printf("Usage: btmgmt %s \n", argv[0]); exit(EXIT_FAILURE); } class[0] = atoi(argv[1]); class[1] = atoi(argv[2]); if (index == MGMT_INDEX_NONE) index = 0; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEV_CLASS, index, class, sizeof(class), class_rsp, NULL) < 0) { fprintf(stderr, "Unable to send set_dev_class cmd\n"); exit(EXIT_FAILURE); } } static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_disconnect *rp = rsp; char addr[18]; if (len == 0 && status != 0) { fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len != sizeof(*rp)) { fprintf(stderr, "Invalid disconnect response length (%u)\n", len); exit(EXIT_FAILURE); } ba2str(&rp->addr.bdaddr, addr); if (status == 0) { printf("%s disconnected\n", addr); exit(EXIT_SUCCESS); } else { fprintf(stderr, "Disconnecting %s failed with status 0x%02x (%s)\n", addr, status, mgmt_errstr(status)); exit(EXIT_FAILURE); } } static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_disconnect cp; if (argc < 2) { printf("Usage: btmgmt %s
\n", argv[0]); exit(EXIT_FAILURE); } str2ba(argv[1], &cp.addr.bdaddr); if (index == MGMT_INDEX_NONE) index = 0; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_DISCONNECT, index, &cp, sizeof(cp), disconnect_rsp, NULL) < 0) { fprintf(stderr, "Unable to send disconnect cmd\n"); exit(EXIT_FAILURE); } } static void con_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_get_connections *rp = rsp; uint16_t count, i; if (len < sizeof(*rp)) { fprintf(stderr, "Too small (%u bytes) get_connections rsp\n", len); exit(EXIT_FAILURE); } count = bt_get_le16(&rp->conn_count); if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) { fprintf(stderr, "Invalid get_connections length " " (count=%u, len=%u)\n", count, len); exit(EXIT_FAILURE); } for (i = 0; i < count; i++) { char addr[18]; ba2str(&rp->addr[i].bdaddr, addr); printf("%s type %s\n", addr, typestr(rp->addr[i].type)); } exit(EXIT_SUCCESS); } static void cmd_con(int mgmt_sk, uint16_t index, int argc, char **argv) { if (index == MGMT_INDEX_NONE) index = 0; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_GET_CONNECTIONS, index, NULL, 0, con_rsp, NULL) < 0) { fprintf(stderr, "Unable to send get_connections cmd\n"); exit(EXIT_FAILURE); } } static void find_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { if (status != 0) { fprintf(stderr, "Unable to start discovery. status 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("Discovery started\n"); discovery = true; } static void find_usage(void) { printf("Usage: btmgmt find [-l|-b]>\n"); } static struct option find_options[] = { { "help", 0, 0, 'h' }, { "le-only", 1, 0, 'l' }, { "bredr-only", 1, 0, 'b' }, { 0, 0, 0, 0 } }; static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_start_discovery cp; uint8_t type; int opt; if (index == MGMT_INDEX_NONE) index = 0; type = 0; hci_set_bit(BDADDR_BREDR, &type); hci_set_bit(BDADDR_LE_PUBLIC, &type); hci_set_bit(BDADDR_LE_RANDOM, &type); while ((opt = getopt_long(argc, argv, "+lbh", find_options, NULL)) != -1) { switch (opt) { case 'l': hci_clear_bit(BDADDR_BREDR, &type); hci_set_bit(BDADDR_LE_PUBLIC, &type); hci_set_bit(BDADDR_LE_RANDOM, &type); break; case 'b': hci_set_bit(BDADDR_BREDR, &type); hci_clear_bit(BDADDR_LE_PUBLIC, &type); hci_clear_bit(BDADDR_LE_RANDOM, &type); break; case 'h': default: find_usage(); exit(EXIT_SUCCESS); } } argc -= optind; argv += optind; optind = 0; memset(&cp, 0, sizeof(cp)); cp.type = type; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_START_DISCOVERY, index, &cp, sizeof(cp), find_rsp, NULL) < 0) { fprintf(stderr, "Unable to send start_discovery cmd\n"); exit(EXIT_FAILURE); } } static void name_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { if (status != 0) { fprintf(stderr, "Unable to set local name. status 0x%02x (%s)", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_set_local_name cp; if (argc < 2) { printf("Usage: btmgmt %s [shortname]\n", argv[0]); exit(EXIT_FAILURE); } if (index == MGMT_INDEX_NONE) index = 0; memset(&cp, 0, sizeof(cp)); strncpy((char *) cp.name, argv[1], HCI_MAX_NAME_LENGTH); if (argc > 2) strncpy((char *) cp.short_name, argv[2], MGMT_MAX_SHORT_NAME_LENGTH); if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_LOCAL_NAME, index, &cp, sizeof(cp), name_rsp, NULL) < 0) { fprintf(stderr, "Unable to send set_name cmd\n"); exit(EXIT_FAILURE); } } static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_pair_device *rp = rsp; char addr[18]; if (len == 0 && status != 0) { fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len != sizeof(*rp)) { fprintf(stderr, "Unexpected pair_rsp len %u\n", len); exit(EXIT_FAILURE); } ba2str(&rp->addr.bdaddr, addr); if (status != 0) { fprintf(stderr, "Pairing with %s (%s) failed. status 0x%02x (%s)\n", addr, typestr(rp->addr.type), status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("Paired with %s\n", addr); exit(EXIT_SUCCESS); } static void pair_usage(void) { printf("Usage: btmgmt pair [-c cap] [-t type] \n"); } static struct option pair_options[] = { { "help", 0, 0, 'h' }, { "capability", 1, 0, 'c' }, { "type", 1, 0, 't' }, { 0, 0, 0, 0 } }; static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_pair_device cp; uint8_t cap = 0x01; uint8_t type = BDADDR_BREDR; int opt; while ((opt = getopt_long(argc, argv, "+c:t:h", pair_options, NULL)) != -1) { switch (opt) { case 'c': cap = strtol(optarg, NULL, 0); break; case 't': type = strtol(optarg, NULL, 0); break; case 'h': default: pair_usage(); exit(EXIT_SUCCESS); } } argc -= optind; argv += optind; optind = 0; if (argc < 1) { pair_usage(); exit(EXIT_FAILURE); } if (index == MGMT_INDEX_NONE) index = 0; memset(&cp, 0, sizeof(cp)); str2ba(argv[0], &cp.addr.bdaddr); cp.addr.type = type; cp.io_cap = cap; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_PAIR_DEVICE, index, &cp, sizeof(cp), pair_rsp, NULL) < 0) { fprintf(stderr, "Unable to send pair_device cmd\n"); exit(EXIT_FAILURE); } } static void unpair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_rp_unpair_device *rp = rsp; char addr[18]; if (len == 0 && status != 0) { fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len != sizeof(*rp)) { fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len); exit(EXIT_FAILURE); } ba2str(&rp->addr.bdaddr, addr); if (status != 0) { fprintf(stderr, "Unpairing %s failed. status 0x%02x (%s)\n", addr, status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("%s unpaired\n", addr); exit(EXIT_SUCCESS); } static void cmd_unpair(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_unpair_device cp; if (argc < 2) { printf("Usage: btmgmt %s \n", argv[0]); exit(EXIT_FAILURE); } if (index == MGMT_INDEX_NONE) index = 0; memset(&cp, 0, sizeof(cp)); str2ba(argv[1], &cp.addr.bdaddr); cp.disconnect = 1; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNPAIR_DEVICE, index, &cp, sizeof(cp), unpair_rsp, NULL) < 0) { fprintf(stderr, "Unable to send unpair_device cmd\n"); exit(EXIT_FAILURE); } } static void keys_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { if (status != 0) { fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("Keys successfully loaded\n"); exit(EXIT_SUCCESS); } static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_load_link_keys cp; if (index == MGMT_INDEX_NONE) index = 0; memset(&cp, 0, sizeof(cp)); if (mgmt_send_cmd(mgmt_sk, MGMT_OP_LOAD_LINK_KEYS, index, &cp, sizeof(cp), keys_rsp, NULL) < 0) { fprintf(stderr, "Unable to send load_keys cmd\n"); exit(EXIT_FAILURE); } } static void block_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { struct mgmt_addr_info *rp = rsp; char addr[18]; if (len == 0 && status != 0) { fprintf(stderr, "%s failed, status 0x%02x (%s)\n", mgmt_opstr(op), status, mgmt_errstr(status)); exit(EXIT_FAILURE); } if (len != sizeof(*rp)) { fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len); exit(EXIT_FAILURE); } ba2str(&rp->bdaddr, addr); if (status != 0) { fprintf(stderr, "%s %s (%s) failed. status 0x%02x (%s)\n", mgmt_opstr(op), addr, typestr(rp->type), status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("%s %s succeeded\n", mgmt_opstr(op), addr); exit(EXIT_SUCCESS); } static void block_usage(void) { printf("Usage: btmgmt block [-t type] \n"); } static struct option block_options[] = { { "help", 0, 0, 'h' }, { "type", 1, 0, 't' }, { 0, 0, 0, 0 } }; static void cmd_block(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_block_device cp; uint8_t type = BDADDR_BREDR; int opt; while ((opt = getopt_long(argc, argv, "+t:h", block_options, NULL)) != -1) { switch (opt) { case 't': type = strtol(optarg, NULL, 0); break; case 'h': default: block_usage(); exit(EXIT_SUCCESS); } } argc -= optind; argv += optind; optind = 0; if (argc < 1) { block_usage(); exit(EXIT_FAILURE); } if (index == MGMT_INDEX_NONE) index = 0; memset(&cp, 0, sizeof(cp)); str2ba(argv[0], &cp.addr.bdaddr); cp.addr.type = type; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_BLOCK_DEVICE, index, &cp, sizeof(cp), block_rsp, NULL) < 0) { fprintf(stderr, "Unable to send block_device cmd\n"); exit(EXIT_FAILURE); } } static void unblock_usage(void) { printf("Usage: btmgmt unblock [-t type] \n"); } static void cmd_unblock(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_unblock_device cp; uint8_t type = BDADDR_BREDR; int opt; while ((opt = getopt_long(argc, argv, "+t:h", block_options, NULL)) != -1) { switch (opt) { case 't': type = strtol(optarg, NULL, 0); break; case 'h': default: unblock_usage(); exit(EXIT_SUCCESS); } } argc -= optind; argv += optind; optind = 0; if (argc < 1) { unblock_usage(); exit(EXIT_FAILURE); } if (index == MGMT_INDEX_NONE) index = 0; memset(&cp, 0, sizeof(cp)); str2ba(argv[0], &cp.addr.bdaddr); cp.addr.type = type; if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNBLOCK_DEVICE, index, &cp, sizeof(cp), block_rsp, NULL) < 0) { fprintf(stderr, "Unable to send unblock_device cmd\n"); exit(EXIT_FAILURE); } } static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid) { if (uuid->type == SDP_UUID16) sdp_uuid16_to_uuid128(uuid128, uuid); else if (uuid->type == SDP_UUID32) sdp_uuid32_to_uuid128(uuid128, uuid); else memcpy(uuid128, uuid, sizeof(*uuid)); } static void cmd_add_uuid(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_add_uuid cp; uint128_t uint128; uuid_t uuid, uuid128; if (argc < 3) { printf("UUID and service hint needed\n"); exit(EXIT_FAILURE); } if (index == MGMT_INDEX_NONE) index = 0; if (bt_string2uuid(&uuid, argv[1]) < 0) { printf("Invalid UUID: %s\n", argv[1]); exit(EXIT_FAILURE); } memset(&cp, 0, sizeof(cp)); uuid_to_uuid128(&uuid128, &uuid); ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128); htob128(&uint128, (uint128_t *) cp.uuid); cp.svc_hint = atoi(argv[2]); if (mgmt_send_cmd(mgmt_sk, MGMT_OP_ADD_UUID, index, &cp, sizeof(cp), class_rsp, NULL) < 0) { fprintf(stderr, "Unable to send add_uuid cmd\n"); exit(EXIT_FAILURE); } } static void cmd_remove_uuid(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_remove_uuid cp; uint128_t uint128; uuid_t uuid, uuid128; if (argc < 2) { printf("UUID needed\n"); exit(EXIT_FAILURE); } if (index == MGMT_INDEX_NONE) index = 0; if (bt_string2uuid(&uuid, argv[1]) < 0) { printf("Invalid UUID: %s\n", argv[1]); exit(EXIT_FAILURE); } memset(&cp, 0, sizeof(cp)); uuid_to_uuid128(&uuid128, &uuid); ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128); htob128(&uint128, (uint128_t *) cp.uuid); if (mgmt_send_cmd(mgmt_sk, MGMT_OP_REMOVE_UUID, index, &cp, sizeof(cp), class_rsp, NULL) < 0) { fprintf(stderr, "Unable to send remove_uuid cmd\n"); exit(EXIT_FAILURE); } } static void cmd_clr_uuids(int mgmt_sk, uint16_t index, int argc, char **argv) { char *uuid_any = "00000000-0000-0000-0000-000000000000"; char *rm_argv[] = { "rm-uuid", uuid_any, NULL }; cmd_remove_uuid(mgmt_sk, index, 2, rm_argv); } static void did_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status, void *rsp, uint16_t len, void *user_data) { if (status != 0) { fprintf(stderr, "Set Device ID failed with status 0x%02x (%s)\n", status, mgmt_errstr(status)); exit(EXIT_FAILURE); } printf("Device ID successfully set\n"); exit(EXIT_SUCCESS); } static void did_usage(void) { printf("Usage: btmgmt did :::\n"); printf(" possible source values: bluetooth, usb\n"); } static void cmd_did(int mgmt_sk, uint16_t index, int argc, char **argv) { struct mgmt_cp_set_device_id cp; uint16_t vendor, product, version , source; int result; if (argc < 2) { did_usage(); exit(EXIT_FAILURE); } result = sscanf(argv[1], "bluetooth:%4hx:%4hx:%4hx", &vendor, &product, &version); if (result == 3) { source = 0x0001; goto done; } result = sscanf(argv[1], "usb:%4hx:%4hx:%4hx", &vendor, &product, &version); if (result == 3) { source = 0x0002; goto done; } did_usage(); exit(EXIT_FAILURE); done: if (index == MGMT_INDEX_NONE) index = 0; cp.source = htobs(source); cp.vendor = htobs(vendor); cp.product = htobs(product); cp.version = htobs(version); if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEVICE_ID, index, &cp, sizeof(cp), did_rsp, NULL) < 0) { fprintf(stderr, "Unable to send set_dev_class cmd\n"); exit(EXIT_FAILURE); } } static struct { char *cmd; void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv); char *doc; } command[] = { { "monitor", cmd_monitor, "Monitor events" }, { "version", cmd_version, "Get the MGMT Version" }, { "commands", cmd_commands, "List supported commands" }, { "info", cmd_info, "Show controller info" }, { "power", cmd_power, "Toggle powered state" }, { "discov", cmd_discov, "Toggle discoverable state" }, { "connectable",cmd_connectable,"Toggle connectable state" }, { "pairable", cmd_pairable, "Toggle pairable state" }, { "linksec", cmd_linksec, "Toggle link level security" }, { "ssp", cmd_ssp, "Toggle SSP mode" }, { "hs", cmd_hs, "Toggle HS Support" }, { "le", cmd_le, "Toggle LE Support" }, { "class", cmd_class, "Set device major/minor class" }, { "disconnect", cmd_disconnect, "Disconnect device" }, { "con", cmd_con, "List connections" }, { "find", cmd_find, "Discover nearby devices" }, { "name", cmd_name, "Set local name" }, { "pair", cmd_pair, "Pair with a remote device" }, { "unpair", cmd_unpair, "Unpair device" }, { "keys", cmd_keys, "Load Keys" }, { "block", cmd_block, "Block Device" }, { "unblock", cmd_unblock, "Unblock Device" }, { "add-uuid", cmd_add_uuid, "Add UUID" }, { "rm-uuid", cmd_add_uuid, "Remove UUID" }, { "clr-uuids", cmd_clr_uuids, "Clear UUIDs", }, { "did", cmd_did, "Set Device ID", }, { NULL, NULL, 0 } }; static void usage(void) { int i; printf("btmgmt ver %s\n", VERSION); printf("Usage:\n" "\tbtmgmt [options] [command parameters]\n"); printf("Options:\n" "\t--index \tSpecify adapter index\n" "\t--verbose\tEnable extra logging\n" "\t--help\tDisplay help\n"); printf("Commands:\n"); for (i = 0; command[i].cmd; i++) printf("\t%-15s\t%s\n", command[i].cmd, command[i].doc); printf("\n" "For more information on the usage of each command use:\n" "\tbtmgmt --help\n" ); } static struct option main_options[] = { { "index", 1, 0, 'i' }, { "verbose", 0, 0, 'v' }, { "help", 0, 0, 'h' }, { 0, 0, 0, 0 } }; int main(int argc, char *argv[]) { int opt, i, mgmt_sk; uint16_t index = MGMT_INDEX_NONE; struct pollfd pollfd; while ((opt = getopt_long(argc, argv, "+hvi:", main_options, NULL)) != -1) { switch (opt) { case 'i': if (strlen(optarg) > 3 && strncasecmp(optarg, "hci", 3) == 0) index = atoi(&optarg[4]); else index = atoi(optarg); break; case 'v': monitor = true; break; case 'h': default: usage(); return 0; } } argc -= optind; argv += optind; optind = 0; if (argc < 1) { usage(); return 0; } mgmt_sk = mgmt_open(); if (mgmt_sk < 0) { fprintf(stderr, "Unable to open mgmt socket\n"); return -1; } for (i = 0; command[i].cmd; i++) { if (strcmp(command[i].cmd, argv[0]) != 0) continue; command[i].func(mgmt_sk, index, argc, argv); break; } if (command[i].cmd == NULL) { fprintf(stderr, "Unknown command: %s\n", argv[0]); close(mgmt_sk); return -1; } pollfd.fd = mgmt_sk; pollfd.events = POLLIN; pollfd.revents = 0; while (poll(&pollfd, 1, -1) >= 0) { if (pollfd.revents & (POLLHUP | POLLERR | POLLNVAL)) break; if (pollfd.revents & POLLIN) mgmt_process_data(mgmt_sk); pollfd.revents = 0; } close(mgmt_sk); return 0; } bluez-4.101/network/0000755000000000000000000000000011771120005011272 500000000000000bluez-4.101/network/connection.c0000644000000000000000000003464111766125764013552 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "log.h" #include "btio.h" #include "dbus-common.h" #include "adapter.h" #include "device.h" #include "error.h" #include "common.h" #include "connection.h" #define NETWORK_PEER_INTERFACE "org.bluez.Network" #define CON_SETUP_RETRIES 3 #define CON_SETUP_TO 9 typedef enum { CONNECTED, CONNECTING, DISCONNECTED } conn_state; struct network_peer { bdaddr_t src; bdaddr_t dst; char *path; /* D-Bus path */ struct btd_device *device; GSList *connections; }; struct network_conn { DBusMessage *msg; char dev[16]; /* Interface name */ uint16_t id; /* Role: Service Class Identifier */ conn_state state; GIOChannel *io; guint watch; /* Disconnect watch */ guint dc_id; struct network_peer *peer; guint attempt_cnt; guint timeout_source; }; struct __service_16 { uint16_t dst; uint16_t src; } __attribute__ ((packed)); static DBusConnection *connection = NULL; static GSList *peers = NULL; static struct network_peer *find_peer(GSList *list, const char *path) { for (; list; list = list->next) { struct network_peer *peer = list->data; if (!strcmp(peer->path, path)) return peer; } return NULL; } static struct network_conn *find_connection(GSList *list, uint16_t id) { for (; list; list = list->next) { struct network_conn *nc = list->data; if (nc->id == id) return nc; } return NULL; } static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct network_conn *nc = data; if (connection != NULL) { gboolean connected = FALSE; const char *property = ""; emit_property_changed(connection, nc->peer->path, NETWORK_PEER_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &connected); emit_property_changed(connection, nc->peer->path, NETWORK_PEER_INTERFACE, "Interface", DBUS_TYPE_STRING, &property); emit_property_changed(connection, nc->peer->path, NETWORK_PEER_INTERFACE, "UUID", DBUS_TYPE_STRING, &property); device_remove_disconnect_watch(nc->peer->device, nc->dc_id); nc->dc_id = 0; if (nc->watch) { g_dbus_remove_watch(connection, nc->watch); nc->watch = 0; } } info("%s disconnected", nc->dev); bnep_if_down(nc->dev); nc->state = DISCONNECTED; memset(nc->dev, 0, sizeof(nc->dev)); strcpy(nc->dev, "bnep%d"); return FALSE; } static void cancel_connection(struct network_conn *nc, const char *err_msg) { DBusMessage *reply; if (nc->timeout_source > 0) { g_source_remove(nc->timeout_source); nc->timeout_source = 0; } if (nc->watch) { g_dbus_remove_watch(connection, nc->watch); nc->watch = 0; } if (nc->msg && err_msg) { reply = btd_error_failed(nc->msg, err_msg); g_dbus_send_message(connection, reply); } g_io_channel_shutdown(nc->io, TRUE, NULL); g_io_channel_unref(nc->io); nc->io = NULL; nc->state = DISCONNECTED; } static void connection_destroy(DBusConnection *conn, void *user_data) { struct network_conn *nc = user_data; if (nc->state == CONNECTED) { bnep_if_down(nc->dev); bnep_kill_connection(&nc->peer->dst); } else if (nc->io) cancel_connection(nc, NULL); } static void disconnect_cb(struct btd_device *device, gboolean removal, void *user_data) { struct network_conn *nc = user_data; info("Network: disconnect %s", nc->peer->path); connection_destroy(NULL, user_data); } static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct network_conn *nc = data; struct bnep_control_rsp *rsp; struct timeval timeo; char pkt[BNEP_MTU]; ssize_t r; int sk; const char *pdev, *uuid; gboolean connected; if (cond & G_IO_NVAL) return FALSE; g_source_remove(nc->timeout_source); nc->timeout_source = 0; if (cond & (G_IO_HUP | G_IO_ERR)) { error("Hangup or error on l2cap server socket"); goto failed; } sk = g_io_channel_unix_get_fd(chan); memset(pkt, 0, BNEP_MTU); r = read(sk, pkt, sizeof(pkt) -1); if (r < 0) { error("IO Channel read error"); goto failed; } if (r == 0) { error("No packet received on l2cap socket"); goto failed; } errno = EPROTO; if ((size_t) r < sizeof(*rsp)) { error("Packet received is not bnep type"); goto failed; } rsp = (void *) pkt; if (rsp->type != BNEP_CONTROL) { error("Packet received is not bnep type"); goto failed; } if (rsp->ctrl != BNEP_SETUP_CONN_RSP) return TRUE; r = ntohs(rsp->resp); if (r != BNEP_SUCCESS) { error("bnep failed"); goto failed; } memset(&timeo, 0, sizeof(timeo)); timeo.tv_sec = 0; setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); if (bnep_connadd(sk, BNEP_SVC_PANU, nc->dev)) { error("%s could not be added", nc->dev); goto failed; } bnep_if_up(nc->dev); pdev = nc->dev; uuid = bnep_uuid(nc->id); g_dbus_send_reply(connection, nc->msg, DBUS_TYPE_STRING, &pdev, DBUS_TYPE_INVALID); connected = TRUE; emit_property_changed(connection, nc->peer->path, NETWORK_PEER_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &connected); emit_property_changed(connection, nc->peer->path, NETWORK_PEER_INTERFACE, "Interface", DBUS_TYPE_STRING, &pdev); emit_property_changed(connection, nc->peer->path, NETWORK_PEER_INTERFACE, "UUID", DBUS_TYPE_STRING, &uuid); nc->state = CONNECTED; nc->dc_id = device_add_disconnect_watch(nc->peer->device, disconnect_cb, nc, NULL); info("%s connected", nc->dev); /* Start watchdog */ g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) bnep_watchdog_cb, nc); g_io_channel_unref(nc->io); nc->io = NULL; return FALSE; failed: cancel_connection(nc, "bnep setup failed"); return FALSE; } static int bnep_send_conn_req(struct network_conn *nc) { struct bnep_setup_conn_req *req; struct __service_16 *s; unsigned char pkt[BNEP_MTU]; int fd; /* Send request */ req = (void *) pkt; req->type = BNEP_CONTROL; req->ctrl = BNEP_SETUP_CONN_REQ; req->uuid_size = 2; /* 16bit UUID */ s = (void *) req->service; s->dst = htons(nc->id); s->src = htons(BNEP_SVC_PANU); fd = g_io_channel_unix_get_fd(nc->io); if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) { int err = -errno; error("bnep connection req send failed: %s", strerror(errno)); return err; } nc->attempt_cnt++; return 0; } static gboolean bnep_conn_req_to(gpointer user_data) { struct network_conn *nc; nc = user_data; if (nc->attempt_cnt == CON_SETUP_RETRIES) { error("Too many bnep connection attempts"); } else { error("bnep connection setup TO, retrying..."); if (!bnep_send_conn_req(nc)) return TRUE; } cancel_connection(nc, "bnep setup failed"); return FALSE; } static int bnep_connect(struct network_conn *nc) { int err; nc->attempt_cnt = 0; if ((err = bnep_send_conn_req(nc))) return err; nc->timeout_source = g_timeout_add_seconds(CON_SETUP_TO, bnep_conn_req_to, nc); g_io_add_watch(nc->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) bnep_setup_cb, nc); return 0; } static void connect_cb(GIOChannel *chan, GError *err, gpointer data) { struct network_conn *nc = data; const char *err_msg; int perr; if (err) { error("%s", err->message); err_msg = err->message; goto failed; } perr = bnep_connect(nc); if (perr < 0) { err_msg = strerror(-perr); error("bnep connect(): %s (%d)", err_msg, -perr); goto failed; } return; failed: cancel_connection(nc, err_msg); } /* Connect and initiate BNEP session */ static DBusMessage *connection_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_peer *peer = data; struct network_conn *nc; const char *svc; uint16_t id; GError *err = NULL; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &svc, DBUS_TYPE_INVALID) == FALSE) return NULL; id = bnep_service_id(svc); nc = find_connection(peer->connections, id); if (!nc) return btd_error_not_supported(msg); if (nc->state != DISCONNECTED) return btd_error_already_connected(msg); nc->io = bt_io_connect(BT_IO_L2CAP, connect_cb, nc, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &peer->src, BT_IO_OPT_DEST_BDADDR, &peer->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) { DBusMessage *reply; error("%s", err->message); reply = btd_error_failed(msg, err->message); g_error_free(err); return reply; } nc->state = CONNECTING; nc->msg = dbus_message_ref(msg); nc->watch = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), connection_destroy, nc, NULL); return NULL; } static DBusMessage *connection_cancel(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_conn *nc = data; const char *owner = dbus_message_get_sender(nc->msg); const char *caller = dbus_message_get_sender(msg); if (!g_str_equal(owner, caller)) return btd_error_not_authorized(msg); connection_destroy(conn, nc); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static DBusMessage *connection_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_peer *peer = data; GSList *l; for (l = peer->connections; l; l = l->next) { struct network_conn *nc = l->data; if (nc->state == DISCONNECTED) continue; return connection_cancel(conn, msg, nc); } return btd_error_not_connected(msg); } static DBusMessage *connection_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_peer *peer = data; struct network_conn *nc = NULL; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; dbus_bool_t connected; const char *property; GSList *l; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Connected */ for (l = peer->connections; l; l = l->next) { struct network_conn *tmp = l->data; if (tmp->state != CONNECTED) continue; nc = tmp; break; } connected = nc ? TRUE : FALSE; dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected); /* Interface */ property = nc ? nc->dev : ""; dict_append_entry(&dict, "Interface", DBUS_TYPE_STRING, &property); /* UUID */ property = nc ? bnep_uuid(nc->id) : ""; dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &property); dbus_message_iter_close_container(&iter, &dict); return reply; } static void connection_free(void *data) { struct network_conn *nc = data; if (nc->dc_id) device_remove_disconnect_watch(nc->peer->device, nc->dc_id); connection_destroy(connection, nc); g_free(nc); nc = NULL; } static void peer_free(struct network_peer *peer) { g_slist_free_full(peer->connections, connection_free); btd_device_unref(peer->device); g_free(peer->path); g_free(peer); } static void path_unregister(void *data) { struct network_peer *peer = data; DBG("Unregistered interface %s on path %s", NETWORK_PEER_INTERFACE, peer->path); peers = g_slist_remove(peers, peer); peer_free(peer); } static const GDBusMethodTable connection_methods[] = { { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, connection_connect) }, { GDBUS_METHOD("Disconnect", NULL, NULL, connection_disconnect) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), connection_get_properties) }, { } }; static const GDBusSignalTable connection_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; void connection_unregister(const char *path, uint16_t id) { struct network_peer *peer; struct network_conn *nc; peer = find_peer(peers, path); if (!peer) return; nc = find_connection(peer->connections, id); if (!nc) return; peer->connections = g_slist_remove(peer->connections, nc); connection_free(nc); if (peer->connections) return; g_dbus_unregister_interface(connection, path, NETWORK_PEER_INTERFACE); } static struct network_peer *create_peer(struct btd_device *device, const char *path, bdaddr_t *src, bdaddr_t *dst) { struct network_peer *peer; peer = g_new0(struct network_peer, 1); peer->device = btd_device_ref(device); peer->path = g_strdup(path); bacpy(&peer->src, src); bacpy(&peer->dst, dst); if (g_dbus_register_interface(connection, path, NETWORK_PEER_INTERFACE, connection_methods, connection_signals, NULL, peer, path_unregister) == FALSE) { error("D-Bus failed to register %s interface", NETWORK_PEER_INTERFACE); peer_free(peer); return NULL; } DBG("Registered interface %s on path %s", NETWORK_PEER_INTERFACE, path); return peer; } int connection_register(struct btd_device *device, const char *path, bdaddr_t *src, bdaddr_t *dst, uint16_t id) { struct network_peer *peer; struct network_conn *nc; if (!path) return -EINVAL; peer = find_peer(peers, path); if (!peer) { peer = create_peer(device, path, src, dst); if (!peer) return -1; peers = g_slist_append(peers, peer); } nc = find_connection(peer->connections, id); if (nc) return 0; nc = g_new0(struct network_conn, 1); nc->id = id; memset(nc->dev, 0, sizeof(nc->dev)); strcpy(nc->dev, "bnep%d"); nc->state = DISCONNECTED; nc->peer = peer; peer->connections = g_slist_append(peer->connections, nc); return 0; } int connection_init(DBusConnection *conn) { connection = dbus_connection_ref(conn); return 0; } void connection_exit(void) { dbus_connection_unref(connection); connection = NULL; } bluez-4.101/network/server.c0000644000000000000000000004233511766125764012720 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "../src/dbus-common.h" #include "../src/adapter.h" #include "log.h" #include "error.h" #include "sdpd.h" #include "btio.h" #include "common.h" #include "server.h" #define NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer" #define SETUP_TIMEOUT 1 /* Pending Authorization */ struct network_session { bdaddr_t dst; /* Remote Bluetooth Address */ GIOChannel *io; /* Pending connect channel */ guint watch; /* BNEP socket watch */ }; struct network_adapter { struct btd_adapter *adapter; /* Adapter pointer */ GIOChannel *io; /* Bnep socket */ struct network_session *setup; /* Setup in progress */ GSList *servers; /* Server register to adapter */ }; /* Main server structure */ struct network_server { bdaddr_t src; /* Bluetooth Local Address */ char *iface; /* DBus interface */ char *name; /* Server service name */ char *bridge; /* Bridge name */ uint32_t record_id; /* Service record id */ uint16_t id; /* Service class identifier */ GSList *sessions; /* Active connections */ struct network_adapter *na; /* Adapter reference */ guint watch_id; /* Client service watch */ }; static DBusConnection *connection = NULL; static GSList *adapters = NULL; static gboolean security = TRUE; static struct network_adapter *find_adapter(GSList *list, struct btd_adapter *adapter) { for (; list; list = list->next) { struct network_adapter *na = list->data; if (na->adapter == adapter) return na; } return NULL; } static struct network_server *find_server(GSList *list, uint16_t id) { for (; list; list = list->next) { struct network_server *ns = list->data; if (ns->id == id) return ns; } return NULL; } static sdp_record_t *server_record_new(const char *name, uint16_t id) { sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto; uuid_t root_uuid, pan, l2cap, bnep; sdp_profile_desc_t profile[1]; sdp_list_t *proto[2]; sdp_data_t *v, *p; uint16_t psm = BNEP_PSM, version = 0x0100; uint16_t security_desc = (security ? 0x0001 : 0x0000); uint16_t net_access_type = 0xfffe; uint32_t max_net_access_rate = 0; const char *desc = "Network service"; sdp_record_t *record; record = sdp_record_alloc(); if (!record) return NULL; record->attrlist = NULL; record->pattern = NULL; switch (id) { case BNEP_SVC_NAP: sdp_uuid16_create(&pan, NAP_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_set_info_attr(record, name, NULL, desc); sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE, SDP_UINT16, &net_access_type); sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE, SDP_UINT32, &max_net_access_rate); break; case BNEP_SVC_GN: sdp_uuid16_create(&pan, GN_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_set_info_attr(record, name, NULL, desc); break; case BNEP_SVC_PANU: sdp_uuid16_create(&pan, PANU_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_set_info_attr(record, name, NULL, desc); break; default: sdp_record_free(record); return NULL; } sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); p = sdp_data_alloc(SDP_UINT16, &psm); proto[0] = sdp_list_append(proto[0], p); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&bnep, BNEP_UUID); proto[1] = sdp_list_append(NULL, &bnep); v = sdp_data_alloc(SDP_UINT16, &version); proto[1] = sdp_list_append(proto[1], v); /* Supported protocols */ { uint16_t ptype[] = { 0x0800, /* IPv4 */ 0x0806, /* ARP */ }; sdp_data_t *head, *pseq; int p; for (p = 0, head = NULL; p < 2; p++) { sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]); if (head) sdp_seq_append(head, data); else head = data; } pseq = sdp_data_alloc(SDP_SEQ16, head); proto[1] = sdp_list_append(proto[1], pseq); } apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); sdp_add_lang_attr(record); sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC, SDP_UINT16, &security_desc); sdp_data_free(p); sdp_data_free(v); sdp_list_free(apseq, NULL); sdp_list_free(root, NULL); sdp_list_free(aproto, NULL); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(svclass, NULL); sdp_list_free(pfseq, NULL); return record; } static ssize_t send_bnep_ctrl_rsp(int sk, uint16_t val) { struct bnep_control_rsp rsp; rsp.type = BNEP_CONTROL; rsp.ctrl = BNEP_SETUP_CONN_RSP; rsp.resp = htons(val); return send(sk, &rsp, sizeof(rsp), 0); } static int server_connadd(struct network_server *ns, struct network_session *session, uint16_t dst_role) { char devname[16]; int err, nsk; memset(devname, 0, sizeof(devname)); strcpy(devname, "bnep%d"); nsk = g_io_channel_unix_get_fd(session->io); err = bnep_connadd(nsk, dst_role, devname); if (err < 0) return err; info("Added new connection: %s", devname); if (bnep_add_to_bridge(devname, ns->bridge) < 0) { error("Can't add %s to the bridge %s: %s(%d)", devname, ns->bridge, strerror(errno), errno); return -EPERM; } bnep_if_up(devname); ns->sessions = g_slist_append(ns->sessions, session); return 0; } static uint16_t bnep_setup_chk(uint16_t dst_role, uint16_t src_role) { /* Allowed PAN Profile scenarios */ switch (dst_role) { case BNEP_SVC_NAP: case BNEP_SVC_GN: if (src_role == BNEP_SVC_PANU) return 0; return BNEP_CONN_INVALID_SRC; case BNEP_SVC_PANU: if (src_role == BNEP_SVC_PANU || src_role == BNEP_SVC_GN || src_role == BNEP_SVC_NAP) return 0; return BNEP_CONN_INVALID_SRC; } return BNEP_CONN_INVALID_DST; } static uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req, uint16_t *dst_role, uint16_t *src_role) { uint8_t *dest, *source; dest = req->service; source = req->service + req->uuid_size; switch (req->uuid_size) { case 2: /* UUID16 */ *dst_role = bt_get_be16(dest); *src_role = bt_get_be16(source); break; case 4: /* UUID32 */ case 16: /* UUID128 */ *dst_role = bt_get_be32(dest); *src_role = bt_get_be32(source); break; default: return BNEP_CONN_INVALID_SVC; } return 0; } static void session_free(void *data) { struct network_session *session = data; if (session->watch) g_source_remove(session->watch); if (session->io) g_io_channel_unref(session->io); g_free(session); } static void setup_destroy(void *user_data) { struct network_adapter *na = user_data; struct network_session *setup = na->setup; if (!setup) return; na->setup = NULL; session_free(setup); } static gboolean bnep_setup(GIOChannel *chan, GIOCondition cond, gpointer user_data) { struct network_adapter *na = user_data; struct network_server *ns; uint8_t packet[BNEP_MTU]; struct bnep_setup_conn_req *req = (void *) packet; uint16_t src_role, dst_role, rsp = BNEP_CONN_NOT_ALLOWED; int n, sk; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_ERR | G_IO_HUP)) { error("Hangup or error on BNEP socket"); return FALSE; } sk = g_io_channel_unix_get_fd(chan); /* Reading BNEP_SETUP_CONNECTION_REQUEST_MSG */ n = read(sk, packet, sizeof(packet)); if (n < 0) { error("read(): %s(%d)", strerror(errno), errno); return FALSE; } /* Highest known Control command ID * is BNEP_FILTER_MULT_ADDR_RSP = 0x06 */ if (req->type == BNEP_CONTROL && req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) { uint8_t pkt[3]; pkt[0] = BNEP_CONTROL; pkt[1] = BNEP_CMD_NOT_UNDERSTOOD; pkt[2] = req->ctrl; send(sk, pkt, sizeof(pkt), 0); return FALSE; } if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ) return FALSE; rsp = bnep_setup_decode(req, &dst_role, &src_role); if (rsp) goto reply; rsp = bnep_setup_chk(dst_role, src_role); if (rsp) goto reply; ns = find_server(na->servers, dst_role); if (!ns) { error("Server unavailable: (0x%x)", dst_role); goto reply; } if (!ns->record_id) { error("Service record not available"); goto reply; } if (!ns->bridge) { error("Bridge interface not configured"); goto reply; } if (server_connadd(ns, na->setup, dst_role) < 0) goto reply; na->setup = NULL; rsp = BNEP_SUCCESS; reply: send_bnep_ctrl_rsp(sk, rsp); return FALSE; } static void connect_event(GIOChannel *chan, GError *err, gpointer user_data) { struct network_adapter *na = user_data; if (err) { error("%s", err->message); setup_destroy(na); return; } g_io_channel_set_close_on_unref(chan, TRUE); na->setup->watch = g_io_add_watch_full(chan, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, bnep_setup, na, setup_destroy); } static void auth_cb(DBusError *derr, void *user_data) { struct network_adapter *na = user_data; GError *err = NULL; if (derr) { error("Access denied: %s", derr->message); goto reject; } if (!bt_io_accept(na->setup->io, connect_event, na, NULL, &err)) { error("bt_io_accept: %s", err->message); g_error_free(err); goto reject; } return; reject: g_io_channel_shutdown(na->setup->io, TRUE, NULL); setup_destroy(na); } static void confirm_event(GIOChannel *chan, gpointer user_data) { struct network_adapter *na = user_data; struct network_server *ns; int perr; bdaddr_t src, dst; char address[18]; GError *err = NULL; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } DBG("BNEP: incoming connect from %s", address); if (na->setup) { error("Refusing connect from %s: setup in progress", address); goto drop; } ns = find_server(na->servers, BNEP_SVC_NAP); if (!ns) goto drop; if (!ns->record_id) goto drop; if (!ns->bridge) goto drop; na->setup = g_new0(struct network_session, 1); bacpy(&na->setup->dst, &dst); na->setup->io = g_io_channel_ref(chan); perr = btd_request_authorization(&src, &dst, BNEP_SVC_UUID, auth_cb, na); if (perr < 0) { error("Refusing connect from %s: %s (%d)", address, strerror(-perr), -perr); setup_destroy(na); goto drop; } return; drop: g_io_channel_shutdown(chan, TRUE, NULL); } int server_init(DBusConnection *conn, gboolean secure) { security = secure; connection = dbus_connection_ref(conn); return 0; } void server_exit(void) { dbus_connection_unref(connection); connection = NULL; } static uint32_t register_server_record(struct network_server *ns) { sdp_record_t *record; record = server_record_new(ns->name, ns->id); if (!record) { error("Unable to allocate new service record"); return 0; } if (add_record_to_server(&ns->src, record) < 0) { error("Failed to register service record"); sdp_record_free(record); return 0; } DBG("got record id 0x%x", record->handle); return record->handle; } static void server_disconnect(DBusConnection *conn, void *user_data) { struct network_server *ns = user_data; ns->watch_id = 0; if (ns->record_id) { remove_record_from_server(ns->record_id); ns->record_id = 0; } g_free(ns->bridge); ns->bridge = NULL; } static DBusMessage *register_server(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_server *ns = data; DBusMessage *reply; const char *uuid, *bridge; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_STRING, &bridge, DBUS_TYPE_INVALID)) return NULL; if (g_strcmp0(uuid, "nap")) return btd_error_failed(msg, "Invalid UUID"); if (ns->record_id) return btd_error_already_exists(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; ns->record_id = register_server_record(ns); if (!ns->record_id) return btd_error_failed(msg, "SDP record registration failed"); g_free(ns->bridge); ns->bridge = g_strdup(bridge); ns->watch_id = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), server_disconnect, ns, NULL); return reply; } static DBusMessage *unregister_server(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_server *ns = data; DBusMessage *reply; const char *uuid; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID)) return NULL; if (g_strcmp0(uuid, "nap")) return btd_error_failed(msg, "Invalid UUID"); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; g_dbus_remove_watch(conn, ns->watch_id); server_disconnect(conn, ns); return reply; } static void adapter_free(struct network_adapter *na) { if (na->io != NULL) { g_io_channel_shutdown(na->io, TRUE, NULL); g_io_channel_unref(na->io); } setup_destroy(na); btd_adapter_unref(na->adapter); g_free(na); } static void server_free(struct network_server *ns) { if (!ns) return; /* FIXME: Missing release/free all bnepX interfaces */ if (ns->record_id) remove_record_from_server(ns->record_id); g_free(ns->iface); g_free(ns->name); g_free(ns->bridge); g_slist_free_full(ns->sessions, session_free); g_free(ns); } static void path_unregister(void *data) { struct network_server *ns = data; struct network_adapter *na = ns->na; DBG("Unregistered interface %s on path %s", ns->iface, adapter_get_path(na->adapter)); na->servers = g_slist_remove(na->servers, ns); server_free(ns); if (na->servers) return; adapters = g_slist_remove(adapters, na); adapter_free(na); } static const GDBusMethodTable server_methods[] = { { GDBUS_METHOD("Register", GDBUS_ARGS({ "uuid", "s" }, { "bridge", "s" }), NULL, register_server) }, { GDBUS_METHOD("Unregister", GDBUS_ARGS({ "uuid", "s" }), NULL, unregister_server) }, { } }; static struct network_adapter *create_adapter(struct btd_adapter *adapter) { struct network_adapter *na; GError *err = NULL; bdaddr_t src; na = g_new0(struct network_adapter, 1); na->adapter = btd_adapter_ref(adapter); adapter_get_address(adapter, &src); na->io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, na, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_PSM, BNEP_PSM, BT_IO_OPT_OMTU, BNEP_MTU, BT_IO_OPT_IMTU, BNEP_MTU, BT_IO_OPT_SEC_LEVEL, security ? BT_IO_SEC_MEDIUM : BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (!na->io) { error("%s", err->message); g_error_free(err); adapter_free(na); return NULL; } return na; } int server_register(struct btd_adapter *adapter) { struct network_adapter *na; struct network_server *ns; const char *path; na = find_adapter(adapters, adapter); if (!na) { na = create_adapter(adapter); if (!na) return -EINVAL; adapters = g_slist_append(adapters, na); } ns = find_server(na->servers, BNEP_SVC_NAP); if (ns) return 0; ns = g_new0(struct network_server, 1); ns->iface = g_strdup(NETWORK_SERVER_INTERFACE); ns->name = g_strdup("Network service"); path = adapter_get_path(adapter); if (!g_dbus_register_interface(connection, path, ns->iface, server_methods, NULL, NULL, ns, path_unregister)) { error("D-Bus failed to register %s interface", ns->iface); server_free(ns); return -1; } adapter_get_address(adapter, &ns->src); ns->id = BNEP_SVC_NAP; ns->na = na; ns->record_id = 0; na->servers = g_slist_append(na->servers, ns); DBG("Registered interface %s on path %s", ns->iface, path); return 0; } int server_unregister(struct btd_adapter *adapter) { struct network_adapter *na; struct network_server *ns; uint16_t id = BNEP_SVC_NAP; na = find_adapter(adapters, adapter); if (!na) return -EINVAL; ns = find_server(na->servers, id); if (!ns) return -EINVAL; g_dbus_unregister_interface(connection, adapter_get_path(adapter), ns->iface); return 0; } bluez-4.101/network/common.h0000644000000000000000000000242011766125764012676 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int bnep_init(void); int bnep_cleanup(void); uint16_t bnep_service_id(const char *svc); const char *bnep_uuid(uint16_t id); const char *bnep_name(uint16_t id); int bnep_kill_connection(bdaddr_t *dst); int bnep_kill_all_connections(void); int bnep_connadd(int sk, uint16_t role, char *dev); int bnep_if_up(const char *devname); int bnep_if_down(const char *devname); int bnep_add_to_bridge(const char *devname, const char *bridge); bluez-4.101/network/main.c0000644000000000000000000000270211376221745012321 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "plugin.h" #include "manager.h" static DBusConnection *connection; static int network_init(void) { connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (connection == NULL) return -EIO; if (network_manager_init(connection) < 0) { dbus_connection_unref(connection); return -EIO; } return 0; } static void network_exit(void) { network_manager_exit(); dbus_connection_unref(connection); } BLUETOOTH_PLUGIN_DEFINE(network, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, network_init, network_exit) bluez-4.101/network/manager.h0000644000000000000000000000165711376221745013024 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int network_manager_init(DBusConnection *conn); void network_manager_exit(void); bluez-4.101/network/connection.h0000644000000000000000000000212411571052274013533 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int connection_init(DBusConnection *conn); void connection_exit(void); int connection_register(struct btd_device *device, const char *path, bdaddr_t *src, bdaddr_t *dst, uint16_t id); void connection_unregister(const char *path, uint16_t id); bluez-4.101/network/common.c0000644000000000000000000001215411766125764012676 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "common.h" static int ctl; static struct { const char *name; /* Friendly name */ const char *uuid128; /* UUID 128 */ uint16_t id; /* Service class identifier */ } __svc[] = { { "panu", PANU_UUID, BNEP_SVC_PANU }, { "gn", GN_UUID, BNEP_SVC_GN }, { "nap", NAP_UUID, BNEP_SVC_NAP }, { NULL } }; uint16_t bnep_service_id(const char *svc) { int i; uint16_t id; /* Friendly service name */ for (i = 0; __svc[i].name; i++) if (!strcasecmp(svc, __svc[i].name)) { return __svc[i].id; } /* UUID 128 string */ for (i = 0; __svc[i].uuid128; i++) if (!strcasecmp(svc, __svc[i].uuid128)) { return __svc[i].id; } /* Try convert to HEX */ id = strtol(svc, NULL, 16); if ((id < BNEP_SVC_PANU) || (id > BNEP_SVC_GN)) return 0; return id; } const char *bnep_uuid(uint16_t id) { int i; for (i = 0; __svc[i].uuid128; i++) if (__svc[i].id == id) return __svc[i].uuid128; return NULL; } const char *bnep_name(uint16_t id) { int i; for (i = 0; __svc[i].name; i++) if (__svc[i].id == id) return __svc[i].name; return NULL; } int bnep_init(void) { ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP); if (ctl < 0) { int err = -errno; error("Failed to open control socket: %s (%d)", strerror(-err), -err); return err; } return 0; } int bnep_cleanup(void) { close(ctl); return 0; } int bnep_kill_connection(bdaddr_t *dst) { struct bnep_conndel_req req; memset(&req, 0, sizeof(req)); baswap((bdaddr_t *)&req.dst, dst); req.flags = 0; if (ioctl(ctl, BNEPCONNDEL, &req)) { int err = -errno; error("Failed to kill connection: %s (%d)", strerror(-err), -err); return err; } return 0; } int bnep_kill_all_connections(void) { struct bnep_connlist_req req; struct bnep_conninfo ci[7]; unsigned int i; int err; memset(&req, 0, sizeof(req)); req.cnum = 7; req.ci = ci; if (ioctl(ctl, BNEPGETCONNLIST, &req)) { err = -errno; error("Failed to get connection list: %s (%d)", strerror(-err), -err); return err; } for (i = 0; i < req.cnum; i++) { struct bnep_conndel_req del; memset(&del, 0, sizeof(del)); memcpy(del.dst, ci[i].dst, ETH_ALEN); del.flags = 0; ioctl(ctl, BNEPCONNDEL, &del); } return 0; } int bnep_connadd(int sk, uint16_t role, char *dev) { struct bnep_connadd_req req; memset(&req, 0, sizeof(req)); strncpy(req.device, dev, 16); req.device[15] = '\0'; req.sock = sk; req.role = role; if (ioctl(ctl, BNEPCONNADD, &req) < 0) { int err = -errno; error("Failed to add device %s: %s(%d)", dev, strerror(-err), -err); return err; } strncpy(dev, req.device, 16); return 0; } int bnep_if_up(const char *devname) { struct ifreq ifr; int sk, err; sk = socket(AF_INET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1); ifr.ifr_flags |= IFF_UP; ifr.ifr_flags |= IFF_MULTICAST; err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr); close(sk); if (err < 0) { error("Could not bring up %s", devname); return err; } return 0; } int bnep_if_down(const char *devname) { struct ifreq ifr; int sk, err; sk = socket(AF_INET, SOCK_DGRAM, 0); memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, devname, IF_NAMESIZE - 1); ifr.ifr_flags &= ~IFF_UP; /* Bring down the interface */ err = ioctl(sk, SIOCSIFFLAGS, (caddr_t) &ifr); close(sk); if (err < 0) { error("Could not bring down %s", devname); return err; } return 0; } int bnep_add_to_bridge(const char *devname, const char *bridge) { int ifindex = if_nametoindex(devname); struct ifreq ifr; int sk, err; if (!devname || !bridge) return -EINVAL; sk = socket(AF_INET, SOCK_STREAM, 0); if (sk < 0) return -1; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1); ifr.ifr_ifindex = ifindex; err = ioctl(sk, SIOCBRADDIF, &ifr); close(sk); if (err < 0) return err; info("bridge %s: interface %s added", bridge, devname); return 0; } bluez-4.101/network/manager.c0000644000000000000000000001206111766125764013015 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "log.h" #include "adapter.h" #include "device.h" #include "manager.h" #include "common.h" #include "connection.h" #include "server.h" static DBusConnection *connection = NULL; static gboolean conf_security = TRUE; static void read_config(const char *file) { GKeyFile *keyfile; GError *err = NULL; keyfile = g_key_file_new(); if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { g_clear_error(&err); goto done; } conf_security = !g_key_file_get_boolean(keyfile, "General", "DisableSecurity", &err); if (err) { DBG("%s: %s", file, err->message); g_clear_error(&err); } done: g_key_file_free(keyfile); DBG("Config options: Security=%s", conf_security ? "true" : "false"); } static int network_probe(struct btd_device *device, GSList *uuids, uint16_t id) { struct btd_adapter *adapter = device_get_adapter(device); const gchar *path = device_get_path(device); bdaddr_t src, dst; DBG("path %s", path); adapter_get_address(adapter, &src); device_get_address(device, &dst, NULL); return connection_register(device, path, &src, &dst, id); } static void network_remove(struct btd_device *device, uint16_t id) { const gchar *path = device_get_path(device); DBG("path %s", path); connection_unregister(path, id); } static int panu_probe(struct btd_device *device, GSList *uuids) { return network_probe(device, uuids, BNEP_SVC_PANU); } static void panu_remove(struct btd_device *device) { network_remove(device, BNEP_SVC_PANU); } static int gn_probe(struct btd_device *device, GSList *uuids) { return network_probe(device, uuids, BNEP_SVC_GN); } static void gn_remove(struct btd_device *device) { network_remove(device, BNEP_SVC_GN); } static int nap_probe(struct btd_device *device, GSList *uuids) { return network_probe(device, uuids, BNEP_SVC_NAP); } static void nap_remove(struct btd_device *device) { network_remove(device, BNEP_SVC_NAP); } static int network_server_probe(struct btd_adapter *adapter) { const gchar *path = adapter_get_path(adapter); DBG("path %s", path); return server_register(adapter); } static void network_server_remove(struct btd_adapter *adapter) { const gchar *path = adapter_get_path(adapter); DBG("path %s", path); server_unregister(adapter); } static struct btd_device_driver network_panu_driver = { .name = "network-panu", .uuids = BTD_UUIDS(PANU_UUID), .probe = panu_probe, .remove = panu_remove, }; static struct btd_device_driver network_gn_driver = { .name = "network-gn", .uuids = BTD_UUIDS(GN_UUID), .probe = gn_probe, .remove = gn_remove, }; static struct btd_device_driver network_nap_driver = { .name = "network-nap", .uuids = BTD_UUIDS(NAP_UUID), .probe = nap_probe, .remove = nap_remove, }; static struct btd_adapter_driver network_server_driver = { .name = "network-server", .probe = network_server_probe, .remove = network_server_remove, }; int network_manager_init(DBusConnection *conn) { read_config(CONFIGDIR "/network.conf"); if (bnep_init()) { error("Can't init bnep module"); return -1; } /* * There is one socket to handle the incoming connections. NAP, * GN and PANU servers share the same PSM. The initial BNEP message * (setup connection request) contains the destination service * field that defines which service the source is connecting to. */ if (server_init(conn, conf_security) < 0) return -1; /* Register network server if it doesn't exist */ btd_register_adapter_driver(&network_server_driver); if (connection_init(conn) < 0) return -1; btd_register_device_driver(&network_panu_driver); btd_register_device_driver(&network_gn_driver); btd_register_device_driver(&network_nap_driver); connection = dbus_connection_ref(conn); return 0; } void network_manager_exit(void) { server_exit(); btd_unregister_device_driver(&network_panu_driver); btd_unregister_device_driver(&network_gn_driver); btd_unregister_device_driver(&network_nap_driver); connection_exit(); btd_unregister_adapter_driver(&network_server_driver); dbus_connection_unref(connection); connection = NULL; bnep_cleanup(); } bluez-4.101/network/server.h0000644000000000000000000000202411766125764012714 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int server_init(DBusConnection *conn, gboolean secure); void server_exit(void); int server_register(struct btd_adapter *adapter); int server_unregister(struct btd_adapter *adapter); bluez-4.101/network/network.conf0000644000000000000000000000017011571052274013562 00000000000000# Configuration file for the network service [General] # Disable link encryption: default=false #DisableSecurity=true bluez-4.101/install-sh0000755000000000000000000003325611771117505011551 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-01-19.21; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # `make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for `test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call `install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for `test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writeable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: bluez-4.101/health/0000755000000000000000000000000011771120004011045 500000000000000bluez-4.101/health/hdp_main.c0000644000000000000000000000270611766125764012743 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "plugin.h" #include "hdp_manager.h" static DBusConnection *connection = NULL; static int hdp_init(void) { connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (connection == NULL) return -EIO; if (hdp_manager_init(connection) < 0) { dbus_connection_unref(connection); return -EIO; } return 0; } static void hdp_exit(void) { hdp_manager_exit(); dbus_connection_unref(connection); connection = NULL; } BLUETOOTH_PLUGIN_DEFINE(health, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, hdp_init, hdp_exit) bluez-4.101/health/mcap_internal.h0000644000000000000000000001074311766125764014005 00000000000000/* * * MCAP for BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __MCAP_INTERNAL_H #define __MCAP_INTERNAL_H #ifdef __cplusplus extern "C" { #endif typedef enum { MCL_CONNECTED, MCL_PENDING, MCL_ACTIVE, MCL_IDLE } MCLState; typedef enum { MCL_ACCEPTOR, MCL_INITIATOR } MCLRole; typedef enum { MCL_AVAILABLE, MCL_WAITING_RSP } MCAPCtrl; typedef enum { MDL_WAITING, MDL_CONNECTED, MDL_DELETING, MDL_CLOSED } MDLState; struct mcap_mdl_cb { mcap_mdl_event_cb mdl_connected; /* Remote device has created a MDL */ mcap_mdl_event_cb mdl_closed; /* Remote device has closed a MDL */ mcap_mdl_event_cb mdl_deleted; /* Remote device requested deleting a MDL */ mcap_mdl_event_cb mdl_aborted; /* Remote device aborted the mdl creation */ mcap_remote_mdl_conn_req_cb mdl_conn_req; /* Remote device requested creating a MDL */ mcap_remote_mdl_reconn_req_cb mdl_reconn_req; /* Remote device requested reconnecting a MDL */ gpointer user_data; /* User data */ }; struct mcap_instance { bdaddr_t src; /* Source address */ GIOChannel *ccio; /* Control Channel IO */ GIOChannel *dcio; /* Data Channel IO */ GSList *mcls; /* MCAP instance list */ GSList *cached; /* List with all cached MCLs (MAX_CACHED macro) */ BtIOSecLevel sec; /* Security level */ mcap_mcl_event_cb mcl_connected_cb; /* New MCL connected */ mcap_mcl_event_cb mcl_reconnected_cb; /* Old MCL has been reconnected */ mcap_mcl_event_cb mcl_disconnected_cb; /* MCL disconnected */ mcap_mcl_event_cb mcl_uncached_cb; /* MCL has been removed from MCAP cache */ mcap_info_ind_event_cb mcl_sync_infoind_cb; /* (CSP Master) Received info indication */ gpointer user_data; /* Data to be provided in callbacks */ gint ref; /* Reference counter */ gboolean csp_enabled; /* CSP: functionality enabled */ }; struct mcap_csp; struct mcap_mdl_op_cb; struct mcap_mcl { struct mcap_instance *mi; /* MCAP instance where this MCL belongs */ bdaddr_t addr; /* Device address */ GIOChannel *cc; /* MCAP Control Channel IO */ guint wid; /* MCL Watcher id */ GSList *mdls; /* List of Data Channels shorted by mdlid */ MCLState state; /* Current MCL State */ MCLRole role; /* Initiator or acceptor of this MCL */ MCAPCtrl req; /* Request control flag */ struct mcap_mdl_op_cb *priv_data; /* Temporal data to manage responses */ struct mcap_mdl_cb *cb; /* MDL callbacks */ guint tid; /* Timer id for waiting for a response */ uint8_t *lcmd; /* Last command sent */ gint ref; /* References counter */ uint8_t ctrl; /* MCL control flag */ uint16_t next_mdl; /* id used to create next MDL */ struct mcap_csp *csp; /* CSP control structure */ }; #define MCAP_CTRL_CACHED 0x01 /* MCL is cached */ #define MCAP_CTRL_STD_OP 0x02 /* Support for standard op codes */ #define MCAP_CTRL_SYNC_OP 0x04 /* Support for synchronization commands */ #define MCAP_CTRL_CONN 0x08 /* MCL is in connecting process */ #define MCAP_CTRL_FREE 0x10 /* MCL is marked as releasable */ #define MCAP_CTRL_NOCACHE 0x20 /* MCL is marked as not cacheable */ struct mcap_mdl { struct mcap_mcl *mcl; /* MCL where this MDL belongs */ GIOChannel *dc; /* MCAP Data Channel IO */ guint wid; /* MDL Watcher id */ uint16_t mdlid; /* MDL id */ uint8_t mdep_id; /* MCAP Data End Point */ MDLState state; /* MDL state */ gint ref; /* References counter */ }; struct sync_info_ind_data { uint32_t btclock; uint64_t timestamp; uint16_t accuracy; }; int mcap_send_data(int sock, const void *buf, uint32_t size); void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len); void mcap_sync_init(struct mcap_mcl *mcl); void mcap_sync_stop(struct mcap_mcl *mcl); #ifdef __cplusplus } #endif #endif /* __MCAP_INTERNAL_H */ bluez-4.101/health/hdp.h0000644000000000000000000000237311766125764011744 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter); void hdp_adapter_unregister(struct btd_adapter *btd_adapter); int hdp_device_register(DBusConnection *conn, struct btd_device *device); void hdp_device_unregister(struct btd_device *device); int hdp_manager_start(DBusConnection *conn); void hdp_manager_stop(void); gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err); bluez-4.101/health/mcap.h0000644000000000000000000000767411766125764012122 00000000000000/* * * MCAP for BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * Copyright (C) 2010 Signove * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __MCAP_H #define __MCAP_H #ifdef __cplusplus extern "C" { #endif #define MCAP_VERSION 0x0100 /* current version 01.00 */ /* bytes to get MCAP Supported Procedures */ #define MCAP_SUP_PROC 0x06 /* maximum transmission unit for channels */ #define MCAP_CC_MTU 48 #define MCAP_DC_MTU L2CAP_DEFAULT_MTU /* MCAP Standard Op Codes */ #define MCAP_ERROR_RSP 0x00 #define MCAP_MD_CREATE_MDL_REQ 0x01 #define MCAP_MD_CREATE_MDL_RSP 0x02 #define MCAP_MD_RECONNECT_MDL_REQ 0x03 #define MCAP_MD_RECONNECT_MDL_RSP 0x04 #define MCAP_MD_ABORT_MDL_REQ 0x05 #define MCAP_MD_ABORT_MDL_RSP 0x06 #define MCAP_MD_DELETE_MDL_REQ 0x07 #define MCAP_MD_DELETE_MDL_RSP 0x08 /* MCAP Clock Sync Op Codes */ #define MCAP_MD_SYNC_CAP_REQ 0x11 #define MCAP_MD_SYNC_CAP_RSP 0x12 #define MCAP_MD_SYNC_SET_REQ 0x13 #define MCAP_MD_SYNC_SET_RSP 0x14 #define MCAP_MD_SYNC_INFO_IND 0x15 /* MCAP Response codes */ #define MCAP_SUCCESS 0x00 #define MCAP_INVALID_OP_CODE 0x01 #define MCAP_INVALID_PARAM_VALUE 0x02 #define MCAP_INVALID_MDEP 0x03 #define MCAP_MDEP_BUSY 0x04 #define MCAP_INVALID_MDL 0x05 #define MCAP_MDL_BUSY 0x06 #define MCAP_INVALID_OPERATION 0x07 #define MCAP_RESOURCE_UNAVAILABLE 0x08 #define MCAP_UNSPECIFIED_ERROR 0x09 #define MCAP_REQUEST_NOT_SUPPORTED 0x0A #define MCAP_CONFIGURATION_REJECTED 0x0B /* MDL IDs */ #define MCAP_MDLID_RESERVED 0x0000 #define MCAP_MDLID_INITIAL 0x0001 #define MCAP_MDLID_FINAL 0xFEFF #define MCAP_ALL_MDLIDS 0xFFFF /* MDEP IDs */ #define MCAP_MDEPID_INITIAL 0x00 #define MCAP_MDEPID_FINAL 0x7F /* CSP special values */ #define MCAP_BTCLOCK_IMMEDIATE 0xffffffffUL #define MCAP_TMSTAMP_DONTSET 0xffffffffffffffffULL #define MCAP_BTCLOCK_MAX 0x0fffffff #define MCAP_BTCLOCK_FIELD (MCAP_BTCLOCK_MAX + 1) /* * MCAP Request Packet Format */ typedef struct { uint8_t op; uint16_t mdl; uint8_t mdep; uint8_t conf; } __attribute__ ((packed)) mcap_md_create_mdl_req; typedef struct { uint8_t op; uint16_t mdl; } __attribute__ ((packed)) mcap_md_req; /* * MCAP Response Packet Format */ typedef struct { uint8_t op; uint8_t rc; uint16_t mdl; uint8_t data[0]; } __attribute__ ((packed)) mcap_rsp; /* * MCAP Clock Synchronization Protocol */ typedef struct { uint8_t op; uint16_t timest; } __attribute__ ((packed)) mcap_md_sync_cap_req; typedef struct { uint8_t op; uint8_t rc; } __attribute__ ((packed)) mcap_md_sync_rsp; typedef struct { uint8_t op; uint8_t rc; uint8_t btclock; uint16_t sltime; uint16_t timestnr; uint16_t timestna; } __attribute__ ((packed)) mcap_md_sync_cap_rsp; typedef struct { uint8_t op; uint8_t timestui; uint32_t btclock; uint64_t timestst; } __attribute__ ((packed)) mcap_md_sync_set_req; typedef struct { int8_t op; uint8_t rc; uint32_t btclock; uint64_t timestst; uint16_t timestsa; } __attribute__ ((packed)) mcap_md_sync_set_rsp; typedef struct { uint8_t op; uint32_t btclock; uint64_t timestst; uint16_t timestsa; } __attribute__ ((packed)) mcap_md_sync_info_ind; #ifdef __cplusplus } #endif #endif /* __MCAP_H */ bluez-4.101/health/hdp_util.c0000644000000000000000000006567311766125764013010 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "mcap.h" #include "mcap_lib.h" #include "hdp_types.h" #include "hdp.h" #include "hdp_util.h" typedef gboolean (*parse_item_f)(DBusMessageIter *iter, gpointer user_data, GError **err); struct dict_entry_func { char *key; parse_item_f func; }; struct get_mdep_data { struct hdp_application *app; gpointer data; hdp_continue_mdep_f func; GDestroyNotify destroy; }; struct conn_mcl_data { int refs; gpointer data; hdp_continue_proc_f func; GDestroyNotify destroy; struct hdp_device *dev; }; struct get_dcpsm_data { gpointer data; hdp_continue_dcpsm_f func; GDestroyNotify destroy; }; static gboolean parse_dict_entry(struct dict_entry_func dict_context[], DBusMessageIter *iter, GError **err, gpointer user_data) { DBusMessageIter entry; char *key; int ctype, i; struct dict_entry_func df; dbus_message_iter_recurse(iter, &entry); ctype = dbus_message_iter_get_arg_type(&entry); if (ctype != DBUS_TYPE_STRING) { g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, "Dictionary entries should have a string as key"); return FALSE; } dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); /* Find function and call it */ for (i = 0, df = dict_context[0]; df.key; i++, df = dict_context[i]) { if (g_ascii_strcasecmp(df.key, key) == 0) return df.func(&entry, user_data, err); } g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, "No function found for parsing value for key %s", key); return FALSE; } static gboolean parse_dict(struct dict_entry_func dict_context[], DBusMessageIter *iter, GError **err, gpointer user_data) { int ctype; DBusMessageIter dict; ctype = dbus_message_iter_get_arg_type(iter); if (ctype != DBUS_TYPE_ARRAY) { g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, "Dictionary should be an array"); return FALSE; } dbus_message_iter_recurse(iter, &dict); while ((ctype = dbus_message_iter_get_arg_type(&dict)) != DBUS_TYPE_INVALID) { if (ctype != DBUS_TYPE_DICT_ENTRY) { g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, "Dictionary array should " "contain dict entries"); return FALSE; } /* Start parsing entry */ if (!parse_dict_entry(dict_context, &dict, err, user_data)) return FALSE; /* Finish entry parsing */ dbus_message_iter_next(&dict); } return TRUE; } static gboolean parse_data_type(DBusMessageIter *iter, gpointer data, GError **err) { struct hdp_application *app = data; DBusMessageIter *value; int ctype; ctype = dbus_message_iter_get_arg_type(iter); value = iter; if (ctype == DBUS_TYPE_VARIANT) { DBusMessageIter variant; /* Get value inside the variable */ dbus_message_iter_recurse(iter, &variant); ctype = dbus_message_iter_get_arg_type(&variant); value = &variant; } if (ctype != DBUS_TYPE_UINT16) { g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, "Final value for data type should be uint16"); return FALSE; } dbus_message_iter_get_basic(value, &app->data_type); app->data_type_set = TRUE; return TRUE; } static gboolean parse_role(DBusMessageIter *iter, gpointer data, GError **err) { struct hdp_application *app = data; DBusMessageIter *string; int ctype; const char *role; ctype = dbus_message_iter_get_arg_type(iter); if (ctype == DBUS_TYPE_VARIANT) { DBusMessageIter value; /* Get value inside the variable */ dbus_message_iter_recurse(iter, &value); ctype = dbus_message_iter_get_arg_type(&value); string = &value; } else { string = iter; } if (ctype != DBUS_TYPE_STRING) { g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR, "Value data spec should be variable or string"); return FALSE; } dbus_message_iter_get_basic(string, &role); if (g_ascii_strcasecmp(role, HDP_SINK_ROLE_AS_STRING) == 0) { app->role = HDP_SINK; } else if (g_ascii_strcasecmp(role, HDP_SOURCE_ROLE_AS_STRING) == 0) { app->role = HDP_SOURCE; } else { g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR, "Role value should be \"source\" or \"sink\""); return FALSE; } app->role_set = TRUE; return TRUE; } static gboolean parse_desc(DBusMessageIter *iter, gpointer data, GError **err) { struct hdp_application *app = data; DBusMessageIter *string; int ctype; const char *desc; ctype = dbus_message_iter_get_arg_type(iter); if (ctype == DBUS_TYPE_VARIANT) { DBusMessageIter variant; /* Get value inside the variable */ dbus_message_iter_recurse(iter, &variant); ctype = dbus_message_iter_get_arg_type(&variant); string = &variant; } else { string = iter; } if (ctype != DBUS_TYPE_STRING) { g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, "Value data spec should be variable or string"); return FALSE; } dbus_message_iter_get_basic(string, &desc); app->description = g_strdup(desc); return TRUE; } static gboolean parse_chan_type(DBusMessageIter *iter, gpointer data, GError **err) { struct hdp_application *app = data; DBusMessageIter *value; char *chan_type; int ctype; ctype = dbus_message_iter_get_arg_type(iter); value = iter; if (ctype == DBUS_TYPE_VARIANT) { DBusMessageIter variant; /* Get value inside the variable */ dbus_message_iter_recurse(iter, &variant); ctype = dbus_message_iter_get_arg_type(&variant); value = &variant; } if (ctype != DBUS_TYPE_STRING) { g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, "Final value for channel type should be an string"); return FALSE; } dbus_message_iter_get_basic(value, &chan_type); if (g_ascii_strcasecmp("Reliable", chan_type) == 0) app->chan_type = HDP_RELIABLE_DC; else if (g_ascii_strcasecmp("Streaming", chan_type) == 0) app->chan_type = HDP_STREAMING_DC; else { g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, "Invalid value for data type"); return FALSE; } app->chan_type_set = TRUE; return TRUE; } static struct dict_entry_func dict_parser[] = { {"DataType", parse_data_type}, {"Role", parse_role}, {"Description", parse_desc}, {"ChannelType", parse_chan_type}, {NULL, NULL} }; struct hdp_application *hdp_get_app_config(DBusMessageIter *iter, GError **err) { struct hdp_application *app; app = g_new0(struct hdp_application, 1); app->ref = 1; if (!parse_dict(dict_parser, iter, err, app)) goto fail; if (!app->data_type_set || !app->role_set) { g_set_error(err, HDP_ERROR, HDP_DIC_PARSE_ERROR, "Mandatory fields aren't set"); goto fail; } return app; fail: hdp_application_unref(app); return NULL; } static gboolean is_app_role(GSList *app_list, HdpRole role) { GSList *l; for (l = app_list; l; l = l->next) { struct hdp_application *app = l->data; if (app->role == role) return TRUE; } return FALSE; } static gboolean set_sdp_services_uuid(sdp_record_t *record, HdpRole role) { uuid_t svc_uuid_source, svc_uuid_sink; sdp_list_t *svc_list = NULL; sdp_uuid16_create(&svc_uuid_sink, HDP_SINK_SVCLASS_ID); sdp_uuid16_create(&svc_uuid_source, HDP_SOURCE_SVCLASS_ID); sdp_get_service_classes(record, &svc_list); if (role == HDP_SOURCE) { if (!sdp_list_find(svc_list, &svc_uuid_source, sdp_uuid_cmp)) svc_list = sdp_list_append(svc_list, &svc_uuid_source); } else if (role == HDP_SINK) { if (!sdp_list_find(svc_list, &svc_uuid_sink, sdp_uuid_cmp)) svc_list = sdp_list_append(svc_list, &svc_uuid_sink); } if (sdp_set_service_classes(record, svc_list) < 0) { sdp_list_free(svc_list, NULL); return FALSE; } sdp_list_free(svc_list, NULL); return TRUE; } static gboolean register_service_protocols(struct hdp_adapter *adapter, sdp_record_t *sdp_record) { gboolean ret; uuid_t l2cap_uuid, mcap_c_uuid; sdp_list_t *l2cap_list, *proto_list = NULL, *mcap_list = NULL; sdp_list_t *access_proto_list = NULL; sdp_data_t *psm = NULL, *mcap_ver = NULL; uint16_t version = MCAP_VERSION; /* set l2cap information */ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append(NULL, &l2cap_uuid); if (l2cap_list == NULL) { ret = FALSE; goto end; } psm = sdp_data_alloc(SDP_UINT16, &adapter->ccpsm); if (psm == NULL) { ret = FALSE; goto end; } if (sdp_list_append(l2cap_list, psm) == NULL) { ret = FALSE; goto end; } proto_list = sdp_list_append(NULL, l2cap_list); if (proto_list == NULL) { ret = FALSE; goto end; } /* set mcap information */ sdp_uuid16_create(&mcap_c_uuid, MCAP_CTRL_UUID); mcap_list = sdp_list_append(NULL, &mcap_c_uuid); if (mcap_list == NULL) { ret = FALSE; goto end; } mcap_ver = sdp_data_alloc(SDP_UINT16, &version); if (mcap_ver == NULL) { ret = FALSE; goto end; } if (sdp_list_append(mcap_list, mcap_ver) == NULL) { ret = FALSE; goto end; } if (sdp_list_append(proto_list, mcap_list) == NULL) { ret = FALSE; goto end; } /* attach protocol information to service record */ access_proto_list = sdp_list_append(NULL, proto_list); if (access_proto_list == NULL) { ret = FALSE; goto end; } if (sdp_set_access_protos(sdp_record, access_proto_list) < 0) { ret = FALSE; goto end; } ret = TRUE; end: if (l2cap_list != NULL) sdp_list_free(l2cap_list, NULL); if (mcap_list != NULL) sdp_list_free(mcap_list, NULL); if (proto_list != NULL) sdp_list_free(proto_list, NULL); if (access_proto_list != NULL) sdp_list_free(access_proto_list, NULL); if (psm != NULL) sdp_data_free(psm); if (mcap_ver != NULL) sdp_data_free(mcap_ver); return ret; } static gboolean register_service_profiles(sdp_record_t *sdp_record) { gboolean ret; sdp_list_t *profile_list; sdp_profile_desc_t hdp_profile; /* set hdp information */ sdp_uuid16_create(&hdp_profile.uuid, HDP_SVCLASS_ID); hdp_profile.version = HDP_VERSION; profile_list = sdp_list_append(NULL, &hdp_profile); if (profile_list == NULL) return FALSE; /* set profile descriptor list */ if (sdp_set_profile_descs(sdp_record, profile_list) < 0) ret = FALSE; else ret = TRUE; sdp_list_free(profile_list, NULL); return ret; } static gboolean register_service_additional_protocols( struct hdp_adapter *adapter, sdp_record_t *sdp_record) { gboolean ret; uuid_t l2cap_uuid, mcap_d_uuid; sdp_list_t *l2cap_list, *proto_list = NULL, *mcap_list = NULL; sdp_list_t *access_proto_list = NULL; sdp_data_t *psm = NULL; /* set l2cap information */ sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); l2cap_list = sdp_list_append(NULL, &l2cap_uuid); if (l2cap_list == NULL) { ret = FALSE; goto end; } psm = sdp_data_alloc(SDP_UINT16, &adapter->dcpsm); if (psm == NULL) { ret = FALSE; goto end; } if (sdp_list_append(l2cap_list, psm) == NULL) { ret = FALSE; goto end; } proto_list = sdp_list_append(NULL, l2cap_list); if (proto_list == NULL) { ret = FALSE; goto end; } /* set mcap information */ sdp_uuid16_create(&mcap_d_uuid, MCAP_DATA_UUID); mcap_list = sdp_list_append(NULL, &mcap_d_uuid); if (mcap_list == NULL) { ret = FALSE; goto end; } if (sdp_list_append(proto_list, mcap_list) == NULL) { ret = FALSE; goto end; } /* attach protocol information to service record */ access_proto_list = sdp_list_append(NULL, proto_list); if (access_proto_list == NULL) { ret = FALSE; goto end; } if (sdp_set_add_access_protos(sdp_record, access_proto_list) < 0) ret = FALSE; else ret = TRUE; end: if (l2cap_list != NULL) sdp_list_free(l2cap_list, NULL); if (mcap_list != NULL) sdp_list_free(mcap_list, NULL); if (proto_list != NULL) sdp_list_free(proto_list, NULL); if (access_proto_list != NULL) sdp_list_free(access_proto_list, NULL); if (psm != NULL) sdp_data_free(psm); return ret; } static sdp_list_t *app_to_sdplist(struct hdp_application *app) { sdp_data_t *mdepid, *dtype = NULL, *role = NULL, *desc = NULL; sdp_list_t *f_list = NULL; mdepid = sdp_data_alloc(SDP_UINT8, &app->id); if (mdepid == NULL) return NULL; dtype = sdp_data_alloc(SDP_UINT16, &app->data_type); if (dtype == NULL) goto fail; role = sdp_data_alloc(SDP_UINT8, &app->role); if (role == NULL) goto fail; if (app->description != NULL) { desc = sdp_data_alloc(SDP_TEXT_STR8, app->description); if (desc == NULL) goto fail; } f_list = sdp_list_append(NULL, mdepid); if (f_list == NULL) goto fail; if (sdp_list_append(f_list, dtype) == NULL) goto fail; if (sdp_list_append(f_list, role) == NULL) goto fail; if (desc != NULL) if (sdp_list_append(f_list, desc) == NULL) goto fail; return f_list; fail: if (f_list != NULL) sdp_list_free(f_list, NULL); if (mdepid != NULL) sdp_data_free(mdepid); if (dtype != NULL) sdp_data_free(dtype); if (role != NULL) sdp_data_free(role); if (desc != NULL) sdp_data_free(desc); return NULL; } static gboolean register_features(struct hdp_application *app, sdp_list_t **sup_features) { sdp_list_t *hdp_feature; hdp_feature = app_to_sdplist(app); if (hdp_feature == NULL) goto fail; if (*sup_features == NULL) { *sup_features = sdp_list_append(NULL, hdp_feature); if (*sup_features == NULL) goto fail; } else if (sdp_list_append(*sup_features, hdp_feature) == NULL) { goto fail; } return TRUE; fail: if (hdp_feature != NULL) sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free); return FALSE; } static void free_hdp_list(void *list) { sdp_list_t *hdp_list = list; sdp_list_free(hdp_list, (sdp_free_func_t)sdp_data_free); } static gboolean register_service_sup_features(GSList *app_list, sdp_record_t *sdp_record) { GSList *l; sdp_list_t *sup_features = NULL; for (l = app_list; l; l = l->next) { if (!register_features(l->data, &sup_features)) return FALSE; } if (sdp_set_supp_feat(sdp_record, sup_features) < 0) { sdp_list_free(sup_features, free_hdp_list); return FALSE; } return TRUE; } static gboolean register_data_exchange_spec(sdp_record_t *record) { sdp_data_t *spec; uint8_t data_spec = DATA_EXCHANGE_SPEC_11073; /* As by now 11073 is the only supported we set it by default */ spec = sdp_data_alloc(SDP_UINT8, &data_spec); if (spec == NULL) return FALSE; if (sdp_attr_add(record, SDP_ATTR_DATA_EXCHANGE_SPEC, spec) < 0) { sdp_data_free(spec); return FALSE; } return TRUE; } static gboolean register_mcap_features(sdp_record_t *sdp_record) { sdp_data_t *mcap_proc; uint8_t mcap_sup_proc = MCAP_SUP_PROC; mcap_proc = sdp_data_alloc(SDP_UINT8, &mcap_sup_proc); if (mcap_proc == NULL) return FALSE; if (sdp_attr_add(sdp_record, SDP_ATTR_MCAP_SUPPORTED_PROCEDURES, mcap_proc) < 0) { sdp_data_free(mcap_proc); return FALSE; } return TRUE; } gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list) { sdp_record_t *sdp_record; bdaddr_t addr; if (adapter->sdp_handler > 0) remove_record_from_server(adapter->sdp_handler); if (app_list == NULL) { adapter->sdp_handler = 0; return TRUE; } sdp_record = sdp_record_alloc(); if (sdp_record == NULL) return FALSE; if (adapter->sdp_handler > 0) sdp_record->handle = adapter->sdp_handler; else sdp_record->handle = 0xffffffff; /* Set automatically */ if (is_app_role(app_list, HDP_SINK)) set_sdp_services_uuid(sdp_record, HDP_SINK); if (is_app_role(app_list, HDP_SOURCE)) set_sdp_services_uuid(sdp_record, HDP_SOURCE); if (!register_service_protocols(adapter, sdp_record)) goto fail; if (!register_service_profiles(sdp_record)) goto fail; if (!register_service_additional_protocols(adapter, sdp_record)) goto fail; sdp_set_info_attr(sdp_record, HDP_SERVICE_NAME, HDP_SERVICE_PROVIDER, HDP_SERVICE_DSC); if (!register_service_sup_features(app_list, sdp_record)) goto fail; if (!register_data_exchange_spec(sdp_record)) goto fail; register_mcap_features(sdp_record); if (sdp_set_record_state(sdp_record, adapter->record_state++) < 0) goto fail; adapter_get_address(adapter->btd_adapter, &addr); if (add_record_to_server(&addr, sdp_record) < 0) goto fail; adapter->sdp_handler = sdp_record->handle; return TRUE; fail: if (sdp_record != NULL) sdp_record_free(sdp_record); return FALSE; } static gboolean check_role(uint8_t rec_role, uint8_t app_role) { if ((rec_role == HDP_SINK && app_role == HDP_SOURCE) || (rec_role == HDP_SOURCE && app_role == HDP_SINK)) return TRUE; return FALSE; } static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role, uint16_t d_type, uint8_t *mdep, char **desc) { sdp_data_t *list, *feat; if (desc == NULL && mdep == NULL) return TRUE; list = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST); if (list == NULL || (list->dtd != SDP_SEQ8 && list->dtd != SDP_SEQ16 && list->dtd != SDP_SEQ32)) return FALSE; for (feat = list->val.dataseq; feat; feat = feat->next) { sdp_data_t *data_type, *mdepid, *role_t, *desc_t; if (feat->dtd != SDP_SEQ8 && feat->dtd != SDP_SEQ16 && feat->dtd != SDP_SEQ32) continue; mdepid = feat->val.dataseq; if (mdepid == NULL) continue; data_type = mdepid->next; if (data_type == NULL) continue; role_t = data_type->next; if (role_t == NULL) continue; desc_t = role_t->next; if (data_type->dtd != SDP_UINT16 || mdepid->dtd != SDP_UINT8 || role_t->dtd != SDP_UINT8) continue; if (data_type->val.uint16 != d_type || !check_role(role_t->val.uint8, role)) continue; if (mdep != NULL) *mdep = mdepid->val.uint8; if (desc != NULL && desc_t != NULL && (desc_t->dtd == SDP_TEXT_STR8 || desc_t->dtd == SDP_TEXT_STR16 || desc_t->dtd == SDP_TEXT_STR32)) *desc = g_strdup(desc_t->val.str); return TRUE; } return FALSE; } static void get_mdep_cb(sdp_list_t *recs, int err, gpointer user_data) { struct get_mdep_data *mdep_data = user_data; GError *gerr = NULL; uint8_t mdep; if (err < 0 || recs == NULL) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Error getting remote SDP records"); mdep_data->func(0, mdep_data->data, gerr); g_error_free(gerr); return; } if (!get_mdep_from_rec(recs->data, mdep_data->app->role, mdep_data->app->data_type, &mdep, NULL)) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "No matching MDEP found"); mdep_data->func(0, mdep_data->data, gerr); g_error_free(gerr); return; } mdep_data->func(mdep, mdep_data->data, NULL); } static void free_mdep_data(gpointer data) { struct get_mdep_data *mdep_data = data; if (mdep_data->destroy) mdep_data->destroy(mdep_data->data); hdp_application_unref(mdep_data->app); g_free(mdep_data); } gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app, hdp_continue_mdep_f func, gpointer data, GDestroyNotify destroy, GError **err) { struct get_mdep_data *mdep_data; bdaddr_t dst, src; uuid_t uuid; device_get_address(device->dev, &dst, NULL); adapter_get_address(device_get_adapter(device->dev), &src); mdep_data = g_new0(struct get_mdep_data, 1); mdep_data->app = hdp_application_ref(app); mdep_data->func = func; mdep_data->data = data; mdep_data->destroy = destroy; bt_string2uuid(&uuid, HDP_UUID); if (bt_search_service(&src, &dst, &uuid, get_mdep_cb, mdep_data, free_mdep_data) < 0) { g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, "Can't get remote SDP record"); g_free(mdep_data); return FALSE; } return TRUE; } static gboolean get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val) { sdp_data_t *iter; int proto; if (entry == NULL || (entry->dtd != SDP_SEQ8 && entry->dtd != SDP_SEQ16 && entry->dtd != SDP_SEQ32)) return FALSE; iter = entry->val.dataseq; if (!(iter->dtd & SDP_UUID_UNSPEC)) return FALSE; proto = sdp_uuid_to_proto(&iter->val.uuid); if (proto != type) return FALSE; if (val == NULL) return TRUE; iter = iter->next; if (iter->dtd != SDP_UINT16) return FALSE; *val = iter->val.uint16; return TRUE; } static gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm, guint16 *version) { sdp_data_t *pdl, *p0, *p1; if (psm == NULL && version == NULL) return TRUE; pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST); if (pdl == NULL || (pdl->dtd != SDP_SEQ8 && pdl->dtd != SDP_SEQ16 && pdl->dtd != SDP_SEQ32)) return FALSE; p0 = pdl->val.dataseq; if (!get_prot_desc_entry(p0, L2CAP_UUID, psm)) return FALSE; p1 = p0->next; if (!get_prot_desc_entry(p1, MCAP_CTRL_UUID, version)) return FALSE; return TRUE; } static gboolean hdp_get_add_prot_desc_list(const sdp_record_t *rec, guint16 *psm) { sdp_data_t *pdl, *p0, *p1; if (psm == NULL) return TRUE; pdl = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST); if (pdl == NULL || pdl->dtd != SDP_SEQ8) return FALSE; pdl = pdl->val.dataseq; if (pdl->dtd != SDP_SEQ8) return FALSE; p0 = pdl->val.dataseq; if (!get_prot_desc_entry(p0, L2CAP_UUID, psm)) return FALSE; p1 = p0->next; if (!get_prot_desc_entry(p1, MCAP_DATA_UUID, NULL)) return FALSE; return TRUE; } static gboolean get_ccpsm(sdp_list_t *recs, uint16_t *ccpsm) { sdp_list_t *l; for (l = recs; l; l = l->next) { sdp_record_t *rec = l->data; if (hdp_get_prot_desc_list(rec, ccpsm, NULL)) return TRUE; } return FALSE; } static gboolean get_dcpsm(sdp_list_t *recs, uint16_t *dcpsm) { sdp_list_t *l; for (l = recs; l; l = l->next) { sdp_record_t *rec = l->data; if (hdp_get_add_prot_desc_list(rec, dcpsm)) return TRUE; } return FALSE; } static void con_mcl_data_unref(struct conn_mcl_data *conn_data) { if (conn_data == NULL) return; if (--conn_data->refs > 0) return; if (conn_data->destroy) conn_data->destroy(conn_data->data); health_device_unref(conn_data->dev); g_free(conn_data); } static void destroy_con_mcl_data(gpointer data) { con_mcl_data_unref(data); } static struct conn_mcl_data *con_mcl_data_ref(struct conn_mcl_data *conn_data) { if (conn_data == NULL) return NULL; conn_data->refs++; return conn_data; } static void create_mcl_cb(struct mcap_mcl *mcl, GError *err, gpointer data) { struct conn_mcl_data *conn_data = data; struct hdp_device *device = conn_data->dev; GError *gerr = NULL; if (err != NULL) { conn_data->func(conn_data->data, err); return; } if (device->mcl == NULL) device->mcl = mcap_mcl_ref(mcl); device->mcl_conn = TRUE; hdp_set_mcl_cb(device, &gerr); conn_data->func(conn_data->data, gerr); if (gerr != NULL) g_error_free(gerr); } static void search_cb(sdp_list_t *recs, int err, gpointer user_data) { struct conn_mcl_data *conn_data = user_data; GError *gerr = NULL; bdaddr_t dst; uint16_t ccpsm; if (conn_data->dev->hdp_adapter->mi == NULL) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Mcap instance released"); goto fail; } if (err < 0 || recs == NULL) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Error getting remote SDP records"); goto fail; } if (!get_ccpsm(recs, &ccpsm)) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Can't get remote PSM for control channel"); goto fail; } conn_data = con_mcl_data_ref(conn_data); device_get_address(conn_data->dev->dev, &dst, NULL); if (!mcap_create_mcl(conn_data->dev->hdp_adapter->mi, &dst, ccpsm, create_mcl_cb, conn_data, destroy_con_mcl_data, &gerr)) { con_mcl_data_unref(conn_data); goto fail; } return; fail: conn_data->func(conn_data->data, gerr); g_error_free(gerr); } gboolean hdp_establish_mcl(struct hdp_device *device, hdp_continue_proc_f func, gpointer data, GDestroyNotify destroy, GError **err) { struct conn_mcl_data *conn_data; bdaddr_t dst, src; uuid_t uuid; device_get_address(device->dev, &dst, NULL); adapter_get_address(device_get_adapter(device->dev), &src); conn_data = g_new0(struct conn_mcl_data, 1); conn_data->refs = 1; conn_data->func = func; conn_data->data = data; conn_data->destroy = destroy; conn_data->dev = health_device_ref(device); bt_string2uuid(&uuid, HDP_UUID); if (bt_search_service(&src, &dst, &uuid, search_cb, conn_data, destroy_con_mcl_data) < 0) { g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, "Can't get remote SDP record"); g_free(conn_data); return FALSE; } return TRUE; } static void get_dcpsm_cb(sdp_list_t *recs, int err, gpointer data) { struct get_dcpsm_data *dcpsm_data = data; GError *gerr = NULL; uint16_t dcpsm; if (err < 0 || recs == NULL) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Error getting remote SDP records"); goto fail; } if (!get_dcpsm(recs, &dcpsm)) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Can't get remote PSM for data channel"); goto fail; } dcpsm_data->func(dcpsm, dcpsm_data->data, NULL); return; fail: dcpsm_data->func(0, dcpsm_data->data, gerr); g_error_free(gerr); } static void free_dcpsm_data(gpointer data) { struct get_dcpsm_data *dcpsm_data = data; if (dcpsm_data == NULL) return; if (dcpsm_data->destroy) dcpsm_data->destroy(dcpsm_data->data); g_free(dcpsm_data); } gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func, gpointer data, GDestroyNotify destroy, GError **err) { struct get_dcpsm_data *dcpsm_data; bdaddr_t dst, src; uuid_t uuid; device_get_address(device->dev, &dst, NULL); adapter_get_address(device_get_adapter(device->dev), &src); dcpsm_data = g_new0(struct get_dcpsm_data, 1); dcpsm_data->func = func; dcpsm_data->data = data; dcpsm_data->destroy = destroy; bt_string2uuid(&uuid, HDP_UUID); if (bt_search_service(&src, &dst, &uuid, get_dcpsm_cb, dcpsm_data, free_dcpsm_data) < 0) { g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, "Can't get remote SDP record"); g_free(dcpsm_data); return FALSE; } return TRUE; } static void hdp_free_application(struct hdp_application *app) { if (app->dbus_watcher > 0) g_dbus_remove_watch(app->conn, app->dbus_watcher); if (app->conn != NULL) dbus_connection_unref(app->conn); g_free(app->oname); g_free(app->description); g_free(app->path); g_free(app); } struct hdp_application *hdp_application_ref(struct hdp_application *app) { if (app == NULL) return NULL; app->ref++; DBG("health_application_ref(%p): ref=%d", app, app->ref); return app; } void hdp_application_unref(struct hdp_application *app) { if (app == NULL) return; app->ref--; DBG("health_application_unref(%p): ref=%d", app, app->ref); if (app->ref > 0) return; hdp_free_application(app); } bluez-4.101/health/mcap_sync.c0000644000000000000000000005357111766125764013146 00000000000000/* * * MCAP for BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * Copyright (C) 2010 Signove * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "mcap.h" #include "mcap_lib.h" #include "mcap_internal.h" #define MCAP_BTCLOCK_HALF (MCAP_BTCLOCK_FIELD / 2) #define CLK CLOCK_MONOTONIC #define MCAP_CSP_ERROR g_quark_from_static_string("mcap-csp-error-quark") #define MAX_RETRIES 10 #define SAMPLE_COUNT 20 struct mcap_csp { uint64_t base_tmstamp; /* CSP base timestamp */ struct timespec base_time; /* CSP base time when timestamp set */ guint local_caps; /* CSP-Master: have got remote caps */ guint remote_caps; /* CSP-Slave: remote master got caps */ guint rem_req_acc; /* CSP-Slave: accuracy required by master */ guint ind_expected; /* CSP-Master: indication expected */ MCAPCtrl csp_req; /* CSP-Master: Request control flag */ guint ind_timer; /* CSP-Slave: indication timer */ guint set_timer; /* CSP-Slave: delayed set timer */ void *set_data; /* CSP-Slave: delayed set data */ void *csp_priv_data; /* CSP-Master: In-flight request data */ }; struct mcap_sync_cap_cbdata { mcap_sync_cap_cb cb; gpointer user_data; }; struct mcap_sync_set_cbdata { mcap_sync_set_cb cb; gpointer user_data; }; struct csp_caps { int ts_acc; /* timestamp accuracy */ int ts_res; /* timestamp resolution */ int latency; /* Read BT clock latency */ int preempt_thresh; /* Preemption threshold for latency */ int syncleadtime_ms; /* SyncLeadTime in ms */ }; struct sync_set_data { uint8_t update; uint32_t sched_btclock; uint64_t timestamp; int ind_freq; gboolean role; }; #define hton64(x) ntoh64(x) static gboolean csp_caps_initialized = FALSE; struct csp_caps _caps; static int send_sync_cmd(struct mcap_mcl *mcl, const void *buf, uint32_t size) { int sock; if (mcl->cc == NULL) return -1; sock = g_io_channel_unix_get_fd(mcl->cc); return mcap_send_data(sock, buf, size); } static int send_unsupported_cap_req(struct mcap_mcl *mcl) { mcap_md_sync_cap_rsp *cmd; int sent; cmd = g_new0(mcap_md_sync_cap_rsp, 1); cmd->op = MCAP_MD_SYNC_CAP_RSP; cmd->rc = MCAP_REQUEST_NOT_SUPPORTED; sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); g_free(cmd); return sent; } static int send_unsupported_set_req(struct mcap_mcl *mcl) { mcap_md_sync_set_rsp *cmd; int sent; cmd = g_new0(mcap_md_sync_set_rsp, 1); cmd->op = MCAP_MD_SYNC_SET_RSP; cmd->rc = MCAP_REQUEST_NOT_SUPPORTED; sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); g_free(cmd); return sent; } static void reset_tmstamp(struct mcap_csp *csp, struct timespec *base_time, uint64_t new_tmstamp) { csp->base_tmstamp = new_tmstamp; if (base_time) csp->base_time = *base_time; else clock_gettime(CLK, &csp->base_time); } void mcap_sync_init(struct mcap_mcl *mcl) { if (!mcl->mi->csp_enabled) { mcl->csp = NULL; return; } mcl->csp = g_new0(struct mcap_csp, 1); mcl->csp->rem_req_acc = 10000; /* safe divisor */ mcl->csp->set_data = NULL; mcl->csp->csp_priv_data = NULL; reset_tmstamp(mcl->csp, NULL, 0); } void mcap_sync_stop(struct mcap_mcl *mcl) { if (!mcl->csp) return; if (mcl->csp->ind_timer) g_source_remove(mcl->csp->ind_timer); if (mcl->csp->set_timer) g_source_remove(mcl->csp->set_timer); if (mcl->csp->set_data) g_free(mcl->csp->set_data); if (mcl->csp->csp_priv_data) g_free(mcl->csp->csp_priv_data); mcl->csp->ind_timer = 0; mcl->csp->set_timer = 0; mcl->csp->set_data = NULL; mcl->csp->csp_priv_data = NULL; g_free(mcl->csp); mcl->csp = NULL; } static uint64_t time_us(struct timespec *tv) { return tv->tv_sec * 1000000 + tv->tv_nsec / 1000; } static int64_t bt2us(int bt) { return bt * 312.5; } static int bt2ms(int bt) { return bt * 312.5 / 1000; } static int btoffset(uint32_t btclk1, uint32_t btclk2) { int offset = btclk2 - btclk1; if (offset <= -MCAP_BTCLOCK_HALF) offset += MCAP_BTCLOCK_FIELD; else if (offset > MCAP_BTCLOCK_HALF) offset -= MCAP_BTCLOCK_FIELD; return offset; } static int btdiff(uint32_t btclk1, uint32_t btclk2) { return btoffset(btclk1, btclk2); } static gboolean valid_btclock(uint32_t btclk) { return btclk <= MCAP_BTCLOCK_MAX; } /* This call may fail; either deal with retry or use read_btclock_retry */ static gboolean read_btclock(struct mcap_mcl *mcl, uint32_t *btclock, uint16_t *btaccuracy) { int which = 1; struct btd_adapter *adapter; adapter = manager_find_adapter(&mcl->mi->src); if (!adapter) return FALSE; if (btd_adapter_read_clock(adapter, &mcl->addr, which, 1000, btclock, btaccuracy) < 0) return FALSE; return TRUE; } static gboolean read_btclock_retry(struct mcap_mcl *mcl, uint32_t *btclock, uint16_t *btaccuracy) { int retries = 5; while (--retries >= 0) { if (read_btclock(mcl, btclock, btaccuracy)) return TRUE; DBG("CSP: retrying to read bt clock..."); } return FALSE; } static gboolean get_btrole(struct mcap_mcl *mcl) { int sock, flags; socklen_t len; if (mcl->cc == NULL) return -1; sock = g_io_channel_unix_get_fd(mcl->cc); len = sizeof(flags); if (getsockopt(sock, SOL_L2CAP, L2CAP_LM, &flags, &len)) DBG("CSP: could not read role"); return flags & L2CAP_LM_MASTER; } uint64_t mcap_get_timestamp(struct mcap_mcl *mcl, struct timespec *given_time) { struct timespec now; uint64_t tmstamp; if (!mcl->csp) return MCAP_TMSTAMP_DONTSET; if (given_time) now = *given_time; else clock_gettime(CLK, &now); tmstamp = time_us(&now) - time_us(&mcl->csp->base_time) + mcl->csp->base_tmstamp; return tmstamp; } uint32_t mcap_get_btclock(struct mcap_mcl *mcl) { uint32_t btclock; uint16_t accuracy; if (!mcl->csp) return MCAP_BTCLOCK_IMMEDIATE; if (!read_btclock_retry(mcl, &btclock, &accuracy)) btclock = 0xffffffff; return btclock; } static gboolean initialize_caps(struct mcap_mcl *mcl) { struct timespec t1, t2; int latencies[SAMPLE_COUNT]; int latency, avg, dev; uint32_t btclock; uint16_t btaccuracy; int i; int retries; clock_getres(CLK, &t1); _caps.ts_res = time_us(&t1); if (_caps.ts_res < 1) _caps.ts_res = 1; _caps.ts_acc = 20; /* ppm, estimated */ /* A little exercise before measuing latency */ clock_gettime(CLK, &t1); read_btclock_retry(mcl, &btclock, &btaccuracy); /* Read clock a number of times and measure latency */ avg = 0; i = 0; retries = MAX_RETRIES; while (i < SAMPLE_COUNT && retries > 0) { clock_gettime(CLK, &t1); if (!read_btclock(mcl, &btclock, &btaccuracy)) { retries--; continue; } clock_gettime(CLK, &t2); latency = time_us(&t2) - time_us(&t1); latencies[i] = latency; avg += latency; i++; } if (retries <= 0) return FALSE; /* Calculate average and deviation */ avg /= SAMPLE_COUNT; dev = 0; for (i = 0; i < SAMPLE_COUNT; ++i) dev += abs(latencies[i] - avg); dev /= SAMPLE_COUNT; /* Calculate corrected average, without 'freak' latencies */ latency = 0; for (i = 0; i < SAMPLE_COUNT; ++i) { if (latencies[i] > (avg + dev * 6)) latency += avg; else latency += latencies[i]; } latency /= SAMPLE_COUNT; _caps.latency = latency; _caps.preempt_thresh = latency * 4; _caps.syncleadtime_ms = latency * 50 / 1000; csp_caps_initialized = TRUE; return TRUE; } static struct csp_caps *caps(struct mcap_mcl *mcl) { if (!csp_caps_initialized) if (!initialize_caps(mcl)) { /* Temporary failure in reading BT clock */ return NULL; } return &_caps; } static int send_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t rspcode, uint8_t btclockres, uint16_t synclead, uint16_t tmstampres, uint16_t tmstampacc) { mcap_md_sync_cap_rsp *rsp; int sent; rsp = g_new0(mcap_md_sync_cap_rsp, 1); rsp->op = MCAP_MD_SYNC_CAP_RSP; rsp->rc = rspcode; rsp->btclock = btclockres; rsp->sltime = htons(synclead); rsp->timestnr = htons(tmstampres); rsp->timestna = htons(tmstampacc); sent = send_sync_cmd(mcl, rsp, sizeof(*rsp)); g_free(rsp); return sent; } static void proc_sync_cap_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { mcap_md_sync_cap_req *req; uint16_t required_accuracy; uint16_t our_accuracy; uint32_t btclock; uint16_t btres; if (len != sizeof(mcap_md_sync_cap_req)) { send_sync_cap_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0, 0); return; } if (!caps(mcl)) { send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, 0, 0, 0, 0); return; } req = (mcap_md_sync_cap_req *) cmd; required_accuracy = ntohs(req->timest); our_accuracy = caps(mcl)->ts_acc; if (required_accuracy < our_accuracy || required_accuracy < 1) { send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, 0, 0, 0, 0); return; } if (!read_btclock_retry(mcl, &btclock, &btres)) { send_sync_cap_rsp(mcl, MCAP_RESOURCE_UNAVAILABLE, 0, 0, 0, 0); return; } mcl->csp->remote_caps = 1; mcl->csp->rem_req_acc = required_accuracy; send_sync_cap_rsp(mcl, MCAP_SUCCESS, btres, caps(mcl)->syncleadtime_ms, caps(mcl)->ts_res, our_accuracy); } static int send_sync_set_rsp(struct mcap_mcl *mcl, uint8_t rspcode, uint32_t btclock, uint64_t timestamp, uint16_t tmstampres) { mcap_md_sync_set_rsp *rsp; int sent; rsp = g_new0(mcap_md_sync_set_rsp, 1); rsp->op = MCAP_MD_SYNC_SET_RSP; rsp->rc = rspcode; rsp->btclock = htonl(btclock); rsp->timestst = hton64(timestamp); rsp->timestsa = htons(tmstampres); sent = send_sync_cmd(mcl, rsp, sizeof(*rsp)); g_free(rsp); return sent; } static gboolean get_all_clocks(struct mcap_mcl *mcl, uint32_t *btclock, struct timespec *base_time, uint64_t *timestamp) { int latency; int retry = 5; uint16_t btres; struct timespec t0; if (!caps(mcl)) return FALSE; latency = caps(mcl)->preempt_thresh + 1; while (latency > caps(mcl)->preempt_thresh && --retry >= 0) { clock_gettime(CLK, &t0); if (!read_btclock(mcl, btclock, &btres)) continue; clock_gettime(CLK, base_time); /* Tries to detect preemption between clock_gettime * and read_btclock by measuring transaction time */ latency = time_us(base_time) - time_us(&t0); } *timestamp = mcap_get_timestamp(mcl, base_time); return TRUE; } static gboolean sync_send_indication(gpointer user_data) { struct mcap_mcl *mcl; mcap_md_sync_info_ind *cmd; uint32_t btclock; uint64_t tmstamp; struct timespec base_time; int sent; if (!user_data) return FALSE; mcl = user_data; if (!caps(mcl)) return FALSE; if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp)) return FALSE; cmd = g_new0(mcap_md_sync_info_ind, 1); cmd->op = MCAP_MD_SYNC_INFO_IND; cmd->btclock = htonl(btclock); cmd->timestst = hton64(tmstamp); cmd->timestsa = htons(caps(mcl)->latency); sent = send_sync_cmd(mcl, cmd, sizeof(*cmd)); g_free(cmd); return !sent; } static gboolean proc_sync_set_req_phase2(gpointer user_data) { struct mcap_mcl *mcl; struct sync_set_data *data; uint8_t update; uint32_t sched_btclock; uint64_t new_tmstamp; int ind_freq; int role; uint32_t btclock; uint64_t tmstamp; struct timespec base_time; uint16_t tmstampacc; gboolean reset; int delay; if (!user_data) return FALSE; mcl = user_data; if (!mcl->csp->set_data) return FALSE; data = mcl->csp->set_data; update = data->update; sched_btclock = data->sched_btclock; new_tmstamp = data->timestamp; ind_freq = data->ind_freq; role = data->role; if (!caps(mcl)) { send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); return FALSE; } if (!get_all_clocks(mcl, &btclock, &base_time, &tmstamp)) { send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); return FALSE; } if (get_btrole(mcl) != role) { send_sync_set_rsp(mcl, MCAP_INVALID_OPERATION, 0, 0, 0); return FALSE; } reset = (new_tmstamp != MCAP_TMSTAMP_DONTSET); if (reset) { if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE) { delay = bt2us(btdiff(sched_btclock, btclock)); if (delay >= 0 || ((new_tmstamp - delay) > 0)) { new_tmstamp += delay; DBG("CSP: reset w/ delay %dus, compensated", delay); } else DBG("CSP: reset w/ delay %dus, uncompensated", delay); } reset_tmstamp(mcl->csp, &base_time, new_tmstamp); tmstamp = new_tmstamp; } tmstampacc = caps(mcl)->latency + caps(mcl)->ts_acc; if (mcl->csp->ind_timer) { g_source_remove(mcl->csp->ind_timer); mcl->csp->ind_timer = 0; } if (update) { int when = ind_freq + caps(mcl)->syncleadtime_ms; mcl->csp->ind_timer = g_timeout_add(when, sync_send_indication, mcl); } send_sync_set_rsp(mcl, MCAP_SUCCESS, btclock, tmstamp, tmstampacc); /* First indication after set is immediate */ if (update) sync_send_indication(mcl); return FALSE; } static void proc_sync_set_req(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { mcap_md_sync_set_req *req; uint32_t sched_btclock, cur_btclock; uint16_t btres; uint8_t update; uint64_t timestamp; struct sync_set_data *set_data; int phase2_delay, ind_freq, when; if (len != sizeof(mcap_md_sync_set_req)) { send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); return; } req = (mcap_md_sync_set_req *) cmd; sched_btclock = ntohl(req->btclock); update = req->timestui; timestamp = ntoh64(req->timestst); if (sched_btclock != MCAP_BTCLOCK_IMMEDIATE && !valid_btclock(sched_btclock)) { send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); return; } if (update > 1) { send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); return; } if (!mcl->csp->remote_caps) { /* Remote side did not ask our capabilities yet */ send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); return; } if (!caps(mcl)) { send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); return; } if (!read_btclock_retry(mcl, &cur_btclock, &btres)) { send_sync_set_rsp(mcl, MCAP_UNSPECIFIED_ERROR, 0, 0, 0); return; } if (sched_btclock == MCAP_BTCLOCK_IMMEDIATE) phase2_delay = 0; else { phase2_delay = btdiff(cur_btclock, sched_btclock); if (phase2_delay < 0) { /* can not reset in the past tense */ send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); return; } /* Convert to miliseconds */ phase2_delay = bt2ms(phase2_delay); if (phase2_delay > 61*1000) { /* More than 60 seconds in the future */ send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); return; } else if (phase2_delay < caps(mcl)->latency / 1000) { /* Too fast for us to do in time */ send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); return; } } if (update) { /* Indication frequency: required accuracy divided by ours */ /* Converted to milisseconds */ ind_freq = (1000 * mcl->csp->rem_req_acc) / caps(mcl)->ts_acc; if (ind_freq < MAX(caps(mcl)->latency * 2 / 1000, 100)) { /* Too frequent, we can't handle */ send_sync_set_rsp(mcl, MCAP_INVALID_PARAM_VALUE, 0, 0, 0); return; } DBG("CSP: indication every %dms", ind_freq); } else ind_freq = 0; if (mcl->csp->ind_timer) { /* Old indications are no longer sent */ g_source_remove(mcl->csp->ind_timer); mcl->csp->ind_timer = 0; } if (!mcl->csp->set_data) mcl->csp->set_data = g_new0(struct sync_set_data, 1); set_data = (struct sync_set_data *) mcl->csp->set_data; set_data->update = update; set_data->sched_btclock = sched_btclock; set_data->timestamp = timestamp; set_data->ind_freq = ind_freq; set_data->role = get_btrole(mcl); /* TODO is there some way to schedule a call based directly on * a BT clock value, instead of this estimation that uses * the SO clock? */ if (phase2_delay > 0) { when = phase2_delay + caps(mcl)->syncleadtime_ms; mcl->csp->set_timer = g_timeout_add(when, proc_sync_set_req_phase2, mcl); } else proc_sync_set_req_phase2(mcl); /* First indication is immediate */ if (update) sync_send_indication(mcl); } static void proc_sync_cap_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { mcap_md_sync_cap_rsp *rsp; uint8_t mcap_err; uint8_t btclockres; uint16_t synclead; uint16_t tmstampres; uint16_t tmstampacc; struct mcap_sync_cap_cbdata *cbdata; mcap_sync_cap_cb cb; gpointer user_data; if (mcl->csp->csp_req != MCAP_MD_SYNC_CAP_REQ) { DBG("CSP: got unexpected cap respose"); return; } if (!mcl->csp->csp_priv_data) { DBG("CSP: no priv data for cap respose"); return; } cbdata = mcl->csp->csp_priv_data; cb = cbdata->cb; user_data = cbdata->user_data; g_free(cbdata); mcl->csp->csp_priv_data = NULL; mcl->csp->csp_req = 0; if (len != sizeof(mcap_md_sync_cap_rsp)) { DBG("CSP: got corrupted cap respose"); return; } rsp = (mcap_md_sync_cap_rsp *) cmd; mcap_err = rsp->rc; btclockres = rsp->btclock; synclead = ntohs(rsp->sltime); tmstampres = ntohs(rsp->timestnr); tmstampacc = ntohs(rsp->timestna); if (!mcap_err) mcl->csp->local_caps = TRUE; cb(mcl, mcap_err, btclockres, synclead, tmstampres, tmstampacc, NULL, user_data); } static void proc_sync_set_rsp(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { mcap_md_sync_set_rsp *rsp; uint8_t mcap_err; uint32_t btclock; uint64_t timestamp; uint16_t accuracy; struct mcap_sync_set_cbdata *cbdata; mcap_sync_set_cb cb; gpointer user_data; if (mcl->csp->csp_req != MCAP_MD_SYNC_SET_REQ) { DBG("CSP: got unexpected set respose"); return; } if (!mcl->csp->csp_priv_data) { DBG("CSP: no priv data for set respose"); return; } cbdata = mcl->csp->csp_priv_data; cb = cbdata->cb; user_data = cbdata->user_data; g_free(cbdata); mcl->csp->csp_priv_data = NULL; mcl->csp->csp_req = 0; if (len != sizeof(mcap_md_sync_set_rsp)) { DBG("CSP: got corrupted set respose"); return; } rsp = (mcap_md_sync_set_rsp *) cmd; mcap_err = rsp->rc; btclock = ntohl(rsp->btclock); timestamp = ntoh64(rsp->timestst); accuracy = ntohs(rsp->timestsa); if (!mcap_err && !valid_btclock(btclock)) mcap_err = MCAP_ERROR_INVALID_ARGS; cb(mcl, mcap_err, btclock, timestamp, accuracy, NULL, user_data); } static void proc_sync_info_ind(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { mcap_md_sync_info_ind *req; struct sync_info_ind_data data; uint32_t btclock; if (!mcl->csp->ind_expected) { DBG("CSP: received unexpected info indication"); return; } if (len != sizeof(mcap_md_sync_info_ind)) return; req = (mcap_md_sync_info_ind *) cmd; btclock = ntohl(req->btclock); if (!valid_btclock(btclock)) return; data.btclock = btclock; data.timestamp = ntoh64(req->timestst); data.accuracy = ntohs(req->timestsa); if (mcl->mi->mcl_sync_infoind_cb) mcl->mi->mcl_sync_infoind_cb(mcl, &data); } void proc_sync_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { if (!mcl->mi->csp_enabled || !mcl->csp) { switch (cmd[0]) { case MCAP_MD_SYNC_CAP_REQ: send_unsupported_cap_req(mcl); break; case MCAP_MD_SYNC_SET_REQ: send_unsupported_set_req(mcl); break; } return; } switch (cmd[0]) { case MCAP_MD_SYNC_CAP_REQ: proc_sync_cap_req(mcl, cmd, len); break; case MCAP_MD_SYNC_CAP_RSP: proc_sync_cap_rsp(mcl, cmd, len); break; case MCAP_MD_SYNC_SET_REQ: proc_sync_set_req(mcl, cmd, len); break; case MCAP_MD_SYNC_SET_RSP: proc_sync_set_rsp(mcl, cmd, len); break; case MCAP_MD_SYNC_INFO_IND: proc_sync_info_ind(mcl, cmd, len); break; } } void mcap_sync_cap_req(struct mcap_mcl *mcl, uint16_t reqacc, mcap_sync_cap_cb cb, gpointer user_data, GError **err) { struct mcap_sync_cap_cbdata *cbdata; mcap_md_sync_cap_req *cmd; if (!mcl->mi->csp_enabled || !mcl->csp) { g_set_error(err, MCAP_CSP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE, "CSP not enabled for the instance"); return; } if (mcl->csp->csp_req) { g_set_error(err, MCAP_CSP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE, "Pending CSP request"); return; } mcl->csp->csp_req = MCAP_MD_SYNC_CAP_REQ; cmd = g_new0(mcap_md_sync_cap_req, 1); cmd->op = MCAP_MD_SYNC_CAP_REQ; cmd->timest = htons(reqacc); cbdata = g_new0(struct mcap_sync_cap_cbdata, 1); cbdata->cb = cb; cbdata->user_data = user_data; mcl->csp->csp_priv_data = cbdata; send_sync_cmd(mcl, cmd, sizeof(*cmd)); g_free(cmd); } void mcap_sync_set_req(struct mcap_mcl *mcl, uint8_t update, uint32_t btclock, uint64_t timestamp, mcap_sync_set_cb cb, gpointer user_data, GError **err) { mcap_md_sync_set_req *cmd; struct mcap_sync_set_cbdata *cbdata; if (!mcl->mi->csp_enabled || !mcl->csp) { g_set_error(err, MCAP_CSP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE, "CSP not enabled for the instance"); return; } if (!mcl->csp->local_caps) { g_set_error(err, MCAP_CSP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE, "Did not get CSP caps from slave yet"); return; } if (mcl->csp->csp_req) { g_set_error(err, MCAP_CSP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE, "Pending CSP request"); return; } mcl->csp->csp_req = MCAP_MD_SYNC_SET_REQ; cmd = g_new0(mcap_md_sync_set_req, 1); cmd->op = MCAP_MD_SYNC_SET_REQ; cmd->timestui = update; cmd->btclock = htonl(btclock); cmd->timestst = hton64(timestamp); mcl->csp->ind_expected = update; cbdata = g_new0(struct mcap_sync_set_cbdata, 1); cbdata->cb = cb; cbdata->user_data = user_data; mcl->csp->csp_priv_data = cbdata; send_sync_cmd(mcl, cmd, sizeof(*cmd)); g_free(cmd); } void mcap_enable_csp(struct mcap_instance *mi) { mi->csp_enabled = TRUE; } void mcap_disable_csp(struct mcap_instance *mi) { mi->csp_enabled = FALSE; } bluez-4.101/health/hdp_manager.c0000644000000000000000000000463511766125764013434 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "hdp_types.h" #include "hdp_manager.h" #include "hdp.h" static DBusConnection *connection = NULL; static int hdp_adapter_probe(struct btd_adapter *adapter) { return hdp_adapter_register(connection, adapter); } static void hdp_adapter_remove(struct btd_adapter *adapter) { hdp_adapter_unregister(adapter); } static struct btd_adapter_driver hdp_adapter_driver = { .name = "hdp-adapter-driver", .probe = hdp_adapter_probe, .remove = hdp_adapter_remove, }; static int hdp_driver_probe(struct btd_device *device, GSList *uuids) { return hdp_device_register(connection, device); } static void hdp_driver_remove(struct btd_device *device) { hdp_device_unregister(device); } static struct btd_device_driver hdp_device_driver = { .name = "hdp-device-driver", .uuids = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID), .probe = hdp_driver_probe, .remove = hdp_driver_remove }; int hdp_manager_init(DBusConnection *conn) { if (hdp_manager_start(conn) < 0) return -1; connection = dbus_connection_ref(conn); btd_register_adapter_driver(&hdp_adapter_driver); btd_register_device_driver(&hdp_device_driver); return 0; } void hdp_manager_exit(void) { btd_unregister_device_driver(&hdp_device_driver); btd_unregister_adapter_driver(&hdp_adapter_driver); hdp_manager_stop(); dbus_connection_unref(connection); connection = NULL; } bluez-4.101/health/mcap.c0000644000000000000000000014152311766125764012105 00000000000000/* * * MCAP for BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include #include #include #include #include "mcap.h" #include "mcap_lib.h" #include "mcap_internal.h" #define RESPONSE_TIMER 6 /* seconds */ #define MAX_CACHED 10 /* 10 devices */ #define MCAP_ERROR g_quark_from_static_string("mcap-error-quark") #define RELEASE_TIMER(__mcl) do { \ if (__mcl->tid) { \ g_source_remove(__mcl->tid); \ __mcl->tid = 0; \ } \ } while(0) struct connect_mcl { struct mcap_mcl *mcl; /* MCL for this operation */ mcap_mcl_connect_cb connect_cb; /* Connect callback */ GDestroyNotify destroy; /* Destroy callback */ gpointer user_data; /* Callback user data */ }; typedef union { mcap_mdl_operation_cb op; mcap_mdl_operation_conf_cb op_conf; mcap_mdl_notify_cb notify; } mcap_cb_type; struct mcap_mdl_op_cb { struct mcap_mdl *mdl; /* MDL for this operation */ mcap_cb_type cb; /* Operation callback */ GDestroyNotify destroy; /* Destroy callback */ gpointer user_data; /* Callback user data */ }; /* MCAP finite state machine functions */ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l); static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l); static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t l); static void (*proc_req[])(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) = { proc_req_connected, proc_req_pending, proc_req_active }; static void mcap_cache_mcl(struct mcap_mcl *mcl); static void default_mdl_connected_cb(struct mcap_mdl *mdl, gpointer data) { DBG("MCAP Unmanaged mdl connection"); } static void default_mdl_closed_cb(struct mcap_mdl *mdl, gpointer data) { DBG("MCAP Unmanaged mdl closed"); } static void default_mdl_deleted_cb(struct mcap_mdl *mdl, gpointer data) { DBG("MCAP Unmanaged mdl deleted"); } static void default_mdl_aborted_cb(struct mcap_mdl *mdl, gpointer data) { DBG("MCAP Unmanaged mdl aborted"); } static uint8_t default_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid, uint16_t mdlid, uint8_t *conf, gpointer data) { DBG("MCAP mdl remote connection aborted"); /* Due to this callback isn't managed this request won't be supported */ return MCAP_REQUEST_NOT_SUPPORTED; } static uint8_t default_mdl_reconn_req_cb(struct mcap_mdl *mdl, gpointer data) { DBG("MCAP mdl remote reconnection aborted"); /* Due to this callback isn't managed this request won't be supported */ return MCAP_REQUEST_NOT_SUPPORTED; } static void set_default_cb(struct mcap_mcl *mcl) { if (!mcl->cb) mcl->cb = g_new0(struct mcap_mdl_cb, 1); mcl->cb->mdl_connected = default_mdl_connected_cb; mcl->cb->mdl_closed = default_mdl_closed_cb; mcl->cb->mdl_deleted = default_mdl_deleted_cb; mcl->cb->mdl_aborted = default_mdl_aborted_cb; mcl->cb->mdl_conn_req = default_mdl_conn_req_cb; mcl->cb->mdl_reconn_req = default_mdl_reconn_req_cb; } static char *error2str(uint8_t rc) { switch (rc) { case MCAP_SUCCESS: return "Success"; case MCAP_INVALID_OP_CODE: return "Invalid Op Code"; case MCAP_INVALID_PARAM_VALUE: return "Invalid Parameter Value"; case MCAP_INVALID_MDEP: return "Invalid MDEP"; case MCAP_MDEP_BUSY: return "MDEP Busy"; case MCAP_INVALID_MDL: return "Invalid MDL"; case MCAP_MDL_BUSY: return "MDL Busy"; case MCAP_INVALID_OPERATION: return "Invalid Operation"; case MCAP_RESOURCE_UNAVAILABLE: return "Resource Unavailable"; case MCAP_UNSPECIFIED_ERROR: return "Unspecified Error"; case MCAP_REQUEST_NOT_SUPPORTED: return "Request Not Supported"; case MCAP_CONFIGURATION_REJECTED: return "Configuration Rejected"; default: return "Unknown Response Code"; } } static gboolean mcap_send_std_opcode(struct mcap_mcl *mcl, void *cmd, uint32_t size, GError **err) { if (mcl->state == MCL_IDLE) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, "MCL is not connected"); return FALSE; } if (mcl->req != MCL_AVAILABLE) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_RESOURCE_UNAVAILABLE, "Pending request"); return FALSE; } if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED, "Remote does not support standard opcodes"); return FALSE; } if (mcl->state == MCL_PENDING) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_OPERATION, "Not Std Op. Codes can be sent in PENDING State"); return FALSE; } if (mcap_send_data(g_io_channel_unix_get_fd(mcl->cc), cmd, size) < 0) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, "Command can't be sent, write error"); return FALSE; } mcl->lcmd = cmd; mcl->req = MCL_WAITING_RSP; return TRUE; } static void update_mcl_state(struct mcap_mcl *mcl) { GSList *l; struct mcap_mdl *mdl; if (mcl->state == MCL_PENDING) return; for (l = mcl->mdls; l; l = l->next) { mdl = l->data; if (mdl->state == MDL_CONNECTED) { mcl->state = MCL_ACTIVE; return; } } mcl->state = MCL_CONNECTED; } static void shutdown_mdl(struct mcap_mdl *mdl) { mdl->state = MDL_CLOSED; if (mdl->wid) { g_source_remove(mdl->wid); mdl->wid = 0; } if (mdl->dc) { g_io_channel_shutdown(mdl->dc, TRUE, NULL); g_io_channel_unref(mdl->dc); mdl->dc = NULL; } } static void free_mdl(struct mcap_mdl *mdl) { if (!mdl) return; mcap_mcl_unref(mdl->mcl); g_free(mdl); } static gint cmp_mdl_state(gconstpointer a, gconstpointer b) { const struct mcap_mdl *mdl = a; const MDLState *st = b; if (mdl->state == *st) return 0; else if (mdl->state < *st) return -1; else return 1; } static void free_mcap_mdl_op(struct mcap_mdl_op_cb *op) { if (op->destroy) op->destroy(op->user_data); if (op->mdl) mcap_mdl_unref(op->mdl); g_free(op); } static void free_mcl_priv_data(struct mcap_mcl *mcl) { free_mcap_mdl_op(mcl->priv_data); mcl->priv_data = NULL; } static void mcap_notify_error(struct mcap_mcl *mcl, GError *err) { struct mcap_mdl_op_cb *con = mcl->priv_data; struct mcap_mdl *mdl; MDLState st; GSList *l; if (!con || !mcl->lcmd) return; switch (mcl->lcmd[0]) { case MCAP_MD_CREATE_MDL_REQ: st = MDL_WAITING; l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); mdl = l->data; mcl->mdls = g_slist_remove(mcl->mdls, mdl); mcap_mdl_unref(mdl); update_mcl_state(mcl); con->cb.op_conf(NULL, 0, err, con->user_data); break; case MCAP_MD_ABORT_MDL_REQ: st = MDL_WAITING; l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); shutdown_mdl(l->data); update_mcl_state(mcl); con->cb.notify(err, con->user_data); break; case MCAP_MD_DELETE_MDL_REQ: for (l = mcl->mdls; l; l = l->next) { mdl = l->data; if (mdl->state == MDL_DELETING) mdl->state = (mdl->dc) ? MDL_CONNECTED : MDL_CLOSED; } update_mcl_state(mcl); con->cb.notify(err, con->user_data); break; case MCAP_MD_RECONNECT_MDL_REQ: st = MDL_WAITING; l = g_slist_find_custom(mcl->mdls, &st, cmp_mdl_state); shutdown_mdl(l->data); update_mcl_state(mcl); con->cb.op(NULL, err, con->user_data); break; } free_mcl_priv_data(mcl); g_free(mcl->lcmd); mcl->lcmd = NULL; } int mcap_send_data(int sock, const void *buf, uint32_t size) { const uint8_t *buf_b = buf; uint32_t sent = 0; while (sent < size) { int n = write(sock, buf_b + sent, size - sent); if (n < 0) return -1; sent += n; } return 0; } static int mcap_send_cmd(struct mcap_mcl *mcl, uint8_t oc, uint8_t rc, uint16_t mdl, uint8_t *data, size_t len) { mcap_rsp *cmd; int sock, sent; if (mcl->cc == NULL) return -1; sock = g_io_channel_unix_get_fd(mcl->cc); cmd = g_malloc(sizeof(mcap_rsp) + len); cmd->op = oc; cmd->rc = rc; cmd->mdl = htons(mdl); if (data && len > 0) memcpy(cmd->data, data, len); sent = mcap_send_data(sock, cmd, sizeof(mcap_rsp) + len); g_free(cmd); return sent; } static struct mcap_mdl *get_mdl(struct mcap_mcl *mcl, uint16_t mdlid) { GSList *l; struct mcap_mdl *mdl; for (l = mcl->mdls; l; l = l->next) { mdl = l->data; if (mdlid == mdl->mdlid) return mdl; } return NULL; } static uint16_t generate_mdlid(struct mcap_mcl *mcl) { uint16_t mdlid = mcl->next_mdl; struct mcap_mdl *mdl; do { mdl = get_mdl(mcl, mdlid); if (!mdl) { mcl->next_mdl = (mdlid % MCAP_MDLID_FINAL) + 1; return mdlid; } else mdlid = (mdlid % MCAP_MDLID_FINAL) + 1; } while (mdlid != mcl->next_mdl); /* No more mdlids availables */ return 0; } static mcap_md_req *create_req(uint8_t op, uint16_t mdl_id) { mcap_md_req *req_cmd; req_cmd = g_new0(mcap_md_req, 1); req_cmd->op = op; req_cmd->mdl = htons(mdl_id); return req_cmd; } static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep, uint8_t conf) { mcap_md_create_mdl_req *req_mdl; req_mdl = g_new0(mcap_md_create_mdl_req, 1); req_mdl->op = MCAP_MD_CREATE_MDL_REQ; req_mdl->mdl = htons(mdl_id); req_mdl->mdep = mdep; req_mdl->conf = conf; return req_mdl; } static gint compare_mdl(gconstpointer a, gconstpointer b) { const struct mcap_mdl *mdla = a; const struct mcap_mdl *mdlb = b; if (mdla->mdlid == mdlb->mdlid) return 0; else if (mdla->mdlid < mdlb->mdlid) return -1; else return 1; } static gboolean wait_response_timer(gpointer data) { struct mcap_mcl *mcl = data; GError *gerr = NULL; RELEASE_TIMER(mcl); g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED, "Timeout waiting response"); mcap_notify_error(mcl, gerr); g_error_free(gerr); mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data); mcap_cache_mcl(mcl); return FALSE; } gboolean mcap_create_mdl(struct mcap_mcl *mcl, uint8_t mdepid, uint8_t conf, mcap_mdl_operation_conf_cb connect_cb, gpointer user_data, GDestroyNotify destroy, GError **err) { struct mcap_mdl *mdl; struct mcap_mdl_op_cb *con; mcap_md_create_mdl_req *cmd; uint16_t id; id = generate_mdlid(mcl); if (!id) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, "Not more mdlids available"); return FALSE; } mdl = g_new0(struct mcap_mdl, 1); mdl->mcl = mcap_mcl_ref(mcl); mdl->mdlid = id; mdl->mdep_id = mdepid; mdl->state = MDL_WAITING; con = g_new0(struct mcap_mdl_op_cb, 1); con->mdl = mcap_mdl_ref(mdl); con->cb.op_conf = connect_cb; con->destroy = destroy; con->user_data = user_data; cmd = create_mdl_req(id, mdepid, conf); if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_create_mdl_req), err)) { mcap_mdl_unref(con->mdl); g_free(con); g_free(cmd); return FALSE; } mcl->state = MCL_ACTIVE; mcl->priv_data = con; mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl), compare_mdl); mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, mcl); return TRUE; } gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl, mcap_mdl_operation_cb reconnect_cb, gpointer user_data, GDestroyNotify destroy, GError **err) { struct mcap_mdl_op_cb *con; struct mcap_mcl *mcl = mdl->mcl; mcap_md_req *cmd; if (mdl->state != MDL_CLOSED) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, "MDL is not closed"); return FALSE; } cmd = create_req(MCAP_MD_RECONNECT_MDL_REQ, mdl->mdlid); if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) { g_free(cmd); return FALSE; } mdl->state = MDL_WAITING; con = g_new0(struct mcap_mdl_op_cb, 1); con->mdl = mcap_mdl_ref(mdl); con->cb.op = reconnect_cb; con->destroy = destroy; con->user_data = user_data; mcl->state = MCL_ACTIVE; mcl->priv_data = con; mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, mcl); return TRUE; } static gboolean send_delete_req(struct mcap_mcl *mcl, struct mcap_mdl_op_cb *con, uint16_t mdlid, GError **err) { mcap_md_req *cmd; cmd = create_req(MCAP_MD_DELETE_MDL_REQ, mdlid); if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) { g_free(cmd); return FALSE; } mcl->priv_data = con; mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, mcl); return TRUE; } gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl, mcap_mdl_notify_cb delete_cb, gpointer user_data, GDestroyNotify destroy, GError **err) { GSList *l; struct mcap_mdl *mdl; struct mcap_mdl_op_cb *con; DBG("MCL in state: %d", mcl->state); if (!mcl->mdls) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, "There are not MDLs created"); return FALSE; } for (l = mcl->mdls; l; l = l->next) { mdl = l->data; if (mdl->state != MDL_WAITING) mdl->state = MDL_DELETING; } con = g_new0(struct mcap_mdl_op_cb, 1); con->mdl = NULL; con->cb.notify = delete_cb; con->destroy = destroy; con->user_data = user_data; if (!send_delete_req(mcl, con, MCAP_ALL_MDLIDS, err)) { g_free(con); return FALSE; } return TRUE; } gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb, gpointer user_data, GDestroyNotify destroy, GError **err) { struct mcap_mcl *mcl= mdl->mcl; struct mcap_mdl_op_cb *con; GSList *l; l = g_slist_find(mcl->mdls, mdl); if (!l) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL, "%s" , error2str(MCAP_INVALID_MDEP)); return FALSE; } if (mdl->state == MDL_WAITING) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, "Mdl is not created"); return FALSE; } mdl->state = MDL_DELETING; con = g_new0(struct mcap_mdl_op_cb, 1); con->mdl = mcap_mdl_ref(mdl); con->cb.notify = delete_cb; con->destroy = destroy; con->user_data = user_data; if (!send_delete_req(mcl, con, mdl->mdlid, err)) { mcap_mdl_unref(con->mdl); g_free(con); return FALSE; } return TRUE; } gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb, gpointer user_data, GDestroyNotify destroy, GError **err) { struct mcap_mdl_op_cb *con; struct mcap_mcl *mcl = mdl->mcl; mcap_md_req *cmd; if (mdl->state != MDL_WAITING) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_FAILED, "Mdl in invalid state"); return FALSE; } cmd = create_req(MCAP_MD_ABORT_MDL_REQ, mdl->mdlid); if (!mcap_send_std_opcode(mcl, cmd, sizeof(mcap_md_req), err)) { g_free(cmd); return FALSE; } con = g_new0(struct mcap_mdl_op_cb, 1); con->mdl = mcap_mdl_ref(mdl); con->cb.notify = abort_cb; con->destroy = destroy; con->user_data = user_data; mcl->priv_data = con; mcl->tid = g_timeout_add_seconds(RESPONSE_TIMER, wait_response_timer, mcl); return TRUE; } static struct mcap_mcl *find_mcl(GSList *list, const bdaddr_t *addr) { struct mcap_mcl *mcl; for (; list; list = list->next) { mcl = list->data; if (!bacmp(&mcl->addr, addr)) return mcl; } return NULL; } int mcap_mdl_get_fd(struct mcap_mdl *mdl) { if (!mdl || mdl->state != MDL_CONNECTED) return -ENOTCONN; return g_io_channel_unix_get_fd(mdl->dc); } uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl) { if (!mdl) return MCAP_MDLID_RESERVED; return mdl->mdlid; } static void close_mcl(struct mcap_mcl *mcl, gboolean cache_requested) { gboolean save = ((!(mcl->ctrl & MCAP_CTRL_FREE)) && cache_requested); RELEASE_TIMER(mcl); if (mcl->cc) { g_io_channel_shutdown(mcl->cc, TRUE, NULL); g_io_channel_unref(mcl->cc); mcl->cc = NULL; } if (mcl->wid) { g_source_remove(mcl->wid); mcl->wid = 0; } if (mcl->lcmd) { g_free(mcl->lcmd); mcl->lcmd = NULL; } if (mcl->priv_data) free_mcl_priv_data(mcl); g_slist_foreach(mcl->mdls, (GFunc) shutdown_mdl, NULL); mcap_sync_stop(mcl); mcl->state = MCL_IDLE; if (save) return; g_slist_foreach(mcl->mdls, (GFunc) mcap_mdl_unref, NULL); g_slist_free(mcl->mdls); mcl->mdls = NULL; } static void mcap_mcl_shutdown(struct mcap_mcl *mcl) { close_mcl(mcl, TRUE); } static void mcap_mcl_release(struct mcap_mcl *mcl) { close_mcl(mcl, FALSE); } static void mcap_cache_mcl(struct mcap_mcl *mcl) { GSList *l; struct mcap_mcl *last; int len; if (mcl->ctrl & MCAP_CTRL_CACHED) return; mcl->mi->mcls = g_slist_remove(mcl->mi->mcls, mcl); if (mcl->ctrl & MCAP_CTRL_NOCACHE) { mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl); mcap_mcl_release(mcl); mcap_mcl_unref(mcl); return; } DBG("Caching MCL"); len = g_slist_length(mcl->mi->cached); if (len == MAX_CACHED) { /* Remove the latest cached mcl */ l = g_slist_last(mcl->mi->cached); last = l->data; mcl->mi->cached = g_slist_remove(mcl->mi->cached, last); last->ctrl &= ~MCAP_CTRL_CACHED; if (last->ctrl & MCAP_CTRL_CONN) { /* We have to release this MCL if */ /* connection is not successful */ last->ctrl |= MCAP_CTRL_FREE; } else { mcap_mcl_release(last); last->mi->mcl_uncached_cb(last, last->mi->user_data); } mcap_mcl_unref(last); } mcl->mi->cached = g_slist_prepend(mcl->mi->cached, mcl); mcl->ctrl |= MCAP_CTRL_CACHED; mcap_mcl_shutdown(mcl); } static void mcap_uncache_mcl(struct mcap_mcl *mcl) { if (!(mcl->ctrl & MCAP_CTRL_CACHED)) return; DBG("Got MCL from cache"); mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl); mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls, mcl); mcl->ctrl &= ~MCAP_CTRL_CACHED; mcl->ctrl &= ~MCAP_CTRL_FREE; } void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache) { if (!mcl) return; if (mcl->ctrl & MCAP_CTRL_FREE) { mcap_mcl_release(mcl); return; } if (!cache) mcl->ctrl |= MCAP_CTRL_NOCACHE; if (mcl->cc) { g_io_channel_shutdown(mcl->cc, TRUE, NULL); g_io_channel_unref(mcl->cc); mcl->cc = NULL; mcl->state = MCL_IDLE; } else if ((mcl->ctrl & MCAP_CTRL_CACHED) && (mcl->ctrl & MCAP_CTRL_NOCACHE)) { mcl->ctrl &= ~MCAP_CTRL_CACHED; mcl->mi->cached = g_slist_remove(mcl->mi->cached, mcl); mcap_mcl_release(mcl); mcap_mcl_unref(mcl); } } struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl) { mcl->ref++; DBG("mcap_mcl_ref(%p): ref=%d", mcl, mcl->ref); return mcl; } void mcap_mcl_unref(struct mcap_mcl *mcl) { mcl->ref--; DBG("mcap_mcl_unref(%p): ref=%d", mcl, mcl->ref); if (mcl->ref > 0) return; mcap_mcl_release(mcl); mcap_instance_unref(mcl->mi); g_free(mcl->cb); g_free(mcl); } static gboolean parse_set_opts(struct mcap_mdl_cb *mdl_cb, GError **err, McapMclCb cb1, va_list args) { McapMclCb cb = cb1; struct mcap_mdl_cb *c; c = g_new0(struct mcap_mdl_cb, 1); while (cb != MCAP_MDL_CB_INVALID) { switch (cb) { case MCAP_MDL_CB_CONNECTED: c->mdl_connected = va_arg(args, mcap_mdl_event_cb); break; case MCAP_MDL_CB_CLOSED: c->mdl_closed = va_arg(args, mcap_mdl_event_cb); break; case MCAP_MDL_CB_DELETED: c->mdl_deleted = va_arg(args, mcap_mdl_event_cb); break; case MCAP_MDL_CB_ABORTED: c->mdl_aborted = va_arg(args, mcap_mdl_event_cb); break; case MCAP_MDL_CB_REMOTE_CONN_REQ: c->mdl_conn_req = va_arg(args, mcap_remote_mdl_conn_req_cb); break; case MCAP_MDL_CB_REMOTE_RECONN_REQ: c->mdl_reconn_req = va_arg(args, mcap_remote_mdl_reconn_req_cb); break; default: g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, "Unknown option %d", cb); g_free(c); return FALSE; } cb = va_arg(args, int); } /* Set new callbacks */ if (c->mdl_connected) mdl_cb->mdl_connected = c->mdl_connected; if (c->mdl_closed) mdl_cb->mdl_closed = c->mdl_closed; if (c->mdl_deleted) mdl_cb->mdl_deleted = c->mdl_deleted; if (c->mdl_aborted) mdl_cb->mdl_aborted = c->mdl_aborted; if (c->mdl_conn_req) mdl_cb->mdl_conn_req = c->mdl_conn_req; if (c->mdl_reconn_req) mdl_cb->mdl_reconn_req = c->mdl_reconn_req; g_free(c); return TRUE; } gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data, GError **gerr, McapMclCb cb1, ...) { va_list args; gboolean ret; va_start(args, cb1); ret = parse_set_opts(mcl->cb, gerr, cb1, args); va_end(args); if (!ret) return FALSE; mcl->cb->user_data = user_data; return TRUE; } void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr) { bacpy(addr, &mcl->addr); } static void mcap_del_mdl(gpointer elem, gpointer user_data) { struct mcap_mdl *mdl = elem; gboolean notify = *(gboolean *) user_data; shutdown_mdl(mdl); if (notify) mdl->mcl->cb->mdl_deleted(mdl, mdl->mcl->cb->user_data); mcap_mdl_unref(mdl); } static gboolean check_cmd_req_length(struct mcap_mcl *mcl, void *cmd, uint32_t rlen, uint32_t explen, uint8_t rspcod) { mcap_md_req *req; uint16_t mdl_id; if (rlen != explen) { if (rlen >= sizeof(mcap_md_req)) { req = cmd; mdl_id = ntohs(req->mdl); } else { /* We can't get mdlid */ mdl_id = MCAP_MDLID_RESERVED; } mcap_send_cmd(mcl, rspcod, MCAP_INVALID_PARAM_VALUE, mdl_id, NULL, 0); return FALSE; } return TRUE; } static void process_md_create_mdl_req(struct mcap_mcl *mcl, void *cmd, uint32_t len) { mcap_md_create_mdl_req *req; struct mcap_mdl *mdl; uint16_t mdl_id; uint8_t mdep_id; uint8_t cfga, conf; uint8_t rsp; if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_create_mdl_req), MCAP_MD_CREATE_MDL_RSP)) return; req = cmd; mdl_id = ntohs(req->mdl); if (mdl_id < MCAP_MDLID_INITIAL || mdl_id > MCAP_MDLID_FINAL) { mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDL, mdl_id, NULL, 0); return; } mdep_id = req->mdep; if (mdep_id > MCAP_MDEPID_FINAL) { mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_INVALID_MDEP, mdl_id, NULL, 0); return; } mdl = get_mdl(mcl, mdl_id); if (mdl && (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING )) { /* Creation request arrives for a MDL that is being managed * at current moment */ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_MDL_BUSY, mdl_id, NULL, 0); return; } cfga = conf = req->conf; /* Callback to upper layer */ rsp = mcl->cb->mdl_conn_req(mcl, mdep_id, mdl_id, &conf, mcl->cb->user_data); if (mcl->state == MCL_IDLE) { /* MCL has been closed int the callback */ return; } if (cfga != 0 && cfga != conf) { /* Remote device set default configuration but upper profile */ /* has changed it. Protocol Error: force closing the MCL by */ /* remote device using UNSPECIFIED_ERROR response */ mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_UNSPECIFIED_ERROR, mdl_id, NULL, 0); return; } if (rsp != MCAP_SUCCESS) { mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, rsp, mdl_id, NULL, 0); return; } if (!mdl) { mdl = g_new0(struct mcap_mdl, 1); mdl->mcl = mcap_mcl_ref(mcl); mdl->mdlid = mdl_id; mcl->mdls = g_slist_insert_sorted(mcl->mdls, mcap_mdl_ref(mdl), compare_mdl); } else if (mdl->state == MDL_CONNECTED) { /* MCAP specification says that we should close the MCL if * it is open when we receive a MD_CREATE_MDL_REQ */ shutdown_mdl(mdl); } mdl->mdep_id = mdep_id; mdl->state = MDL_WAITING; mcl->state = MCL_PENDING; mcap_send_cmd(mcl, MCAP_MD_CREATE_MDL_RSP, MCAP_SUCCESS, mdl_id, &conf, 1); } static void process_md_reconnect_mdl_req(struct mcap_mcl *mcl, void *cmd, uint32_t len) { mcap_md_req *req; struct mcap_mdl *mdl; uint16_t mdl_id; uint8_t rsp; if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req), MCAP_MD_RECONNECT_MDL_RSP)) return; req = cmd; mdl_id = ntohs(req->mdl); mdl = get_mdl(mcl, mdl_id); if (!mdl) { mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_INVALID_MDL, mdl_id, NULL, 0); return; } else if (mdl->state == MDL_WAITING || mdl->state == MDL_DELETING ) { /* Creation request arrives for a MDL that is being managed * at current moment */ mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_MDL_BUSY, mdl_id, NULL, 0); return; } /* Callback to upper layer */ rsp = mcl->cb->mdl_reconn_req(mdl, mcl->cb->user_data); if (mcl->state == MCL_IDLE) return; if (rsp != MCAP_SUCCESS) { mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, rsp, mdl_id, NULL, 0); return; } if (mdl->state == MDL_CONNECTED) shutdown_mdl(mdl); mdl->state = MDL_WAITING; mcl->state = MCL_PENDING; mcap_send_cmd(mcl, MCAP_MD_RECONNECT_MDL_RSP, MCAP_SUCCESS, mdl_id, NULL, 0); } static void process_md_abort_mdl_req(struct mcap_mcl *mcl, void *cmd, uint32_t len) { mcap_md_req *req; GSList *l; struct mcap_mdl *mdl, *abrt; uint16_t mdl_id; if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req), MCAP_MD_ABORT_MDL_RSP)) return; req = cmd; mdl_id = ntohs(req->mdl); mcl->state = MCL_CONNECTED; abrt = NULL; for (l = mcl->mdls; l; l = l->next) { mdl = l->data; if (mdl_id == mdl->mdlid && mdl->state == MDL_WAITING) { abrt = mdl; if (mcl->state != MCL_CONNECTED) break; continue; } if (mdl->state == MDL_CONNECTED && mcl->state != MCL_ACTIVE) mcl->state = MCL_ACTIVE; if (abrt && mcl->state == MCL_ACTIVE) break; } if (!abrt) { mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_INVALID_MDL, mdl_id, NULL, 0); return; } mcl->cb->mdl_aborted(abrt, mcl->cb->user_data); abrt->state = MDL_CLOSED; mcap_send_cmd(mcl, MCAP_MD_ABORT_MDL_RSP, MCAP_SUCCESS, mdl_id, NULL, 0); } static void process_md_delete_mdl_req(struct mcap_mcl *mcl, void *cmd, uint32_t len) { mcap_md_req *req; struct mcap_mdl *mdl, *aux; uint16_t mdlid; gboolean notify; GSList *l; if (!check_cmd_req_length(mcl, cmd, len, sizeof(mcap_md_req), MCAP_MD_DELETE_MDL_RSP)) return; req = cmd; mdlid = ntohs(req->mdl); if (mdlid == MCAP_ALL_MDLIDS) { notify = FALSE; g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify); g_slist_free(mcl->mdls); mcl->mdls = NULL; mcl->state = MCL_CONNECTED; /* NULL mdl means ALL_MDLS */ mcl->cb->mdl_deleted(NULL, mcl->cb->user_data); goto resp; } if (mdlid < MCAP_MDLID_INITIAL || mdlid > MCAP_MDLID_FINAL) { mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL, mdlid, NULL, 0); return; } for (l = mcl->mdls, mdl = NULL; l; l = l->next) { aux = l->data; if (aux->mdlid == mdlid) { mdl = aux; break; } } if (!mdl || mdl->state == MDL_WAITING) { mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_INVALID_MDL, mdlid, NULL, 0); return; } mcl->mdls = g_slist_remove(mcl->mdls, mdl); update_mcl_state(mcl); notify = TRUE; mcap_del_mdl(mdl, ¬ify); resp: mcap_send_cmd(mcl, MCAP_MD_DELETE_MDL_RSP, MCAP_SUCCESS, mdlid, NULL, 0); } static void invalid_req_state(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { uint16_t mdlr; error("Invalid cmd received (op code = %d) in state %d", cmd[0], mcl->state); /* Get previously mdlid sent to generate an appropriate * response if it is possible */ mdlr = len < sizeof(mcap_md_req) ? MCAP_MDLID_RESERVED : ntohs(((mcap_md_req *) cmd)->mdl); mcap_send_cmd(mcl, cmd[0]+1, MCAP_INVALID_OPERATION, mdlr, NULL, 0); } /* Function used to process commands depending of MCL state */ static void proc_req_connected(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { switch (cmd[0]) { case MCAP_MD_CREATE_MDL_REQ: process_md_create_mdl_req(mcl, cmd, len); break; case MCAP_MD_RECONNECT_MDL_REQ: process_md_reconnect_mdl_req(mcl, cmd, len); break; case MCAP_MD_DELETE_MDL_REQ: process_md_delete_mdl_req(mcl, cmd, len); break; default: invalid_req_state(mcl, cmd, len); } } static void proc_req_pending(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { if (cmd[0] == MCAP_MD_ABORT_MDL_REQ) process_md_abort_mdl_req(mcl, cmd, len); else invalid_req_state(mcl, cmd, len); } static void proc_req_active(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { switch (cmd[0]) { case MCAP_MD_CREATE_MDL_REQ: process_md_create_mdl_req(mcl, cmd, len); break; case MCAP_MD_RECONNECT_MDL_REQ: process_md_reconnect_mdl_req(mcl, cmd, len); break; case MCAP_MD_DELETE_MDL_REQ: process_md_delete_mdl_req(mcl, cmd, len); break; default: invalid_req_state(mcl, cmd, len); } } /* Function used to process replies */ static gboolean check_err_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp, uint32_t rlen, uint32_t len, GError **gerr) { mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd; gint err = MCAP_ERROR_FAILED; gboolean close = FALSE; char *msg; if (rsp->op == MCAP_ERROR_RSP) { msg = "MCAP_ERROR_RSP received"; close = FALSE; goto fail; } /* Check if the response matches with the last request */ if (rlen < sizeof(mcap_rsp) || (mcl->lcmd[0] + 1) != rsp->op) { msg = "Protocol error"; close = FALSE; goto fail; } if (rlen < len) { msg = "Protocol error"; close = FALSE; goto fail; } if (rsp->mdl != cmdlast->mdl) { msg = "MDLID received doesn't match with MDLID sent"; close = TRUE; goto fail; } if (rsp->rc == MCAP_REQUEST_NOT_SUPPORTED) { msg = "Remote does not support opcodes"; mcl->ctrl &= ~MCAP_CTRL_STD_OP; goto fail; } if (rsp->rc == MCAP_UNSPECIFIED_ERROR) { msg = "Unspecified error"; close = TRUE; goto fail; } if (rsp->rc != MCAP_SUCCESS) { msg = error2str(rsp->rc); err = rsp->rc; goto fail; } return FALSE; fail: g_set_error(gerr, MCAP_ERROR, err, "%s", msg); return close; } static gboolean process_md_create_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp, uint32_t len) { mcap_md_create_mdl_req *cmdlast = (mcap_md_create_mdl_req *) mcl->lcmd; struct mcap_mdl_op_cb *conn = mcl->priv_data; mcap_mdl_operation_conf_cb connect_cb = conn->cb.op_conf; gpointer user_data = conn->user_data; struct mcap_mdl *mdl = conn->mdl; uint8_t conf = cmdlast->conf; gboolean close; GError *gerr = NULL; close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp) + 1, &gerr); g_free(mcl->lcmd); mcl->lcmd = NULL; mcl->req = MCL_AVAILABLE; if (gerr) goto fail; /* Check if preferences changed */ if (conf != 0x00 && rsp->data[0] != conf) { g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_FAILED, "Configuration changed"); close = TRUE; goto fail; } connect_cb(mdl, rsp->data[0], gerr, user_data); return close; fail: connect_cb(NULL, 0, gerr, user_data); mcl->mdls = g_slist_remove(mcl->mdls, mdl); mcap_mdl_unref(mdl); g_error_free(gerr); update_mcl_state(mcl); return close; } static gboolean process_md_reconnect_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp, uint32_t len) { struct mcap_mdl_op_cb *reconn = mcl->priv_data; mcap_mdl_operation_cb reconn_cb = reconn->cb.op; gpointer user_data = reconn->user_data; struct mcap_mdl *mdl = reconn->mdl; GError *gerr = NULL; gboolean close; close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr); g_free(mcl->lcmd); mcl->lcmd = NULL; mcl->req = MCL_AVAILABLE; reconn_cb(mdl, gerr, user_data); if (!gerr) return close; g_error_free(gerr); shutdown_mdl(mdl); update_mcl_state(mcl); if (rsp->rc != MCAP_INVALID_MDL) return close; /* Remove cached mdlid */ mcl->mdls = g_slist_remove(mcl->mdls, mdl); mcl->cb->mdl_deleted(mdl, mcl->cb->user_data); mcap_mdl_unref(mdl); return close; } static gboolean process_md_abort_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp, uint32_t len) { struct mcap_mdl_op_cb *abrt = mcl->priv_data; mcap_mdl_notify_cb abrt_cb = abrt->cb.notify; gpointer user_data = abrt->user_data; struct mcap_mdl *mdl = abrt->mdl; GError *gerr = NULL; gboolean close; close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr); g_free(mcl->lcmd); mcl->lcmd = NULL; mcl->req = MCL_AVAILABLE; abrt_cb(gerr, user_data); shutdown_mdl(mdl); if (len >= sizeof(mcap_rsp) && rsp->rc == MCAP_INVALID_MDL) { mcl->mdls = g_slist_remove(mcl->mdls, mdl); mcl->cb->mdl_deleted(mdl, mcl->cb->user_data); mcap_mdl_unref(mdl); } if (gerr) g_error_free(gerr); update_mcl_state(mcl); return close; } static void restore_mdl(gpointer elem, gpointer data) { struct mcap_mdl *mdl = elem; if (mdl->state == MDL_DELETING) { if (mdl->dc) mdl->state = MDL_CONNECTED; else mdl->state = MDL_CLOSED; } else if (mdl->state == MDL_CLOSED) mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data); } static void check_mdl_del_err(struct mcap_mdl *mdl, mcap_rsp *rsp) { if (rsp->rc != MCAP_ERROR_INVALID_MDL) { restore_mdl(mdl, NULL); return; } /* MDL does not exist in remote side, we can delete it */ mdl->mcl->mdls = g_slist_remove(mdl->mcl->mdls, mdl); mcap_mdl_unref(mdl); } static gboolean process_md_delete_mdl_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp, uint32_t len) { struct mcap_mdl_op_cb *del = mcl->priv_data; struct mcap_mdl *mdl = del->mdl; mcap_mdl_notify_cb deleted_cb = del->cb.notify; gpointer user_data = del->user_data; mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd; uint16_t mdlid = ntohs(cmdlast->mdl); GError *gerr = NULL; gboolean close; gboolean notify = FALSE; close = check_err_rsp(mcl, rsp, len, sizeof(mcap_rsp), &gerr); g_free(mcl->lcmd); mcl->lcmd = NULL; mcl->req = MCL_AVAILABLE; if (gerr) { if (mdl) check_mdl_del_err(mdl, rsp); else g_slist_foreach(mcl->mdls, restore_mdl, NULL); deleted_cb(gerr, user_data); g_error_free(gerr); return close; } if (mdlid == MCAP_ALL_MDLIDS) { g_slist_foreach(mcl->mdls, mcap_del_mdl, ¬ify); g_slist_free(mcl->mdls); mcl->mdls = NULL; mcl->state = MCL_CONNECTED; } else { mcl->mdls = g_slist_remove(mcl->mdls, mdl); update_mcl_state(mcl); mcap_del_mdl(mdl, ¬ify); } deleted_cb(gerr, user_data); return close; } static void post_process_rsp(struct mcap_mcl *mcl, struct mcap_mdl_op_cb *op) { if (mcl->priv_data != op) { /* Queued MCAP request in some callback. */ /* We should not delete the mcl private data */ free_mcap_mdl_op(op); } else { /* This is not a queued request. It's safe */ /* delete the mcl private data here. */ free_mcl_priv_data(mcl); } } static void proc_response(struct mcap_mcl *mcl, void *buf, uint32_t len) { struct mcap_mdl_op_cb *op = mcl->priv_data; mcap_rsp *rsp = buf; gboolean close; RELEASE_TIMER(mcl); switch (mcl->lcmd[0] + 1) { case MCAP_MD_CREATE_MDL_RSP: close = process_md_create_mdl_rsp(mcl, rsp, len); post_process_rsp(mcl, op); break; case MCAP_MD_RECONNECT_MDL_RSP: close = process_md_reconnect_mdl_rsp(mcl, rsp, len); post_process_rsp(mcl, op); break; case MCAP_MD_ABORT_MDL_RSP: close = process_md_abort_mdl_rsp(mcl, rsp, len); post_process_rsp(mcl, op); break; case MCAP_MD_DELETE_MDL_RSP: close = process_md_delete_mdl_rsp(mcl, rsp, len); post_process_rsp(mcl, op); break; default: DBG("Unknown cmd response received (op code = %d)", rsp->op); close = TRUE; break; } if (close) { mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data); mcap_cache_mcl(mcl); } } static void proc_cmd(struct mcap_mcl *mcl, uint8_t *cmd, uint32_t len) { GError *gerr = NULL; if (cmd[0] > MCAP_MD_SYNC_INFO_IND || (cmd[0] > MCAP_MD_DELETE_MDL_RSP && cmd[0] < MCAP_MD_SYNC_CAP_REQ)) { error("Unknown cmd received (op code = %d)", cmd[0]); mcap_send_cmd(mcl, MCAP_ERROR_RSP, MCAP_INVALID_OP_CODE, MCAP_MDLID_RESERVED, NULL, 0); return; } if (cmd[0] >= MCAP_MD_SYNC_CAP_REQ && cmd[0] <= MCAP_MD_SYNC_INFO_IND) { proc_sync_cmd(mcl, cmd, len); return; } if (!(mcl->ctrl & MCAP_CTRL_STD_OP)) { /* In case the remote device doesn't work correctly */ error("Remote device does not support opcodes, cmd ignored"); return; } if (mcl->req == MCL_WAITING_RSP) { if (cmd[0] & 0x01) { /* Request arrived when a response is expected */ if (mcl->role == MCL_INITIATOR) /* ignore */ return; /* Initiator will ignore our last request */ RELEASE_TIMER(mcl); mcl->req = MCL_AVAILABLE; g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_REQ_IGNORED, "Initiator sent a request with more priority"); mcap_notify_error(mcl, gerr); proc_req[mcl->state](mcl, cmd, len); return; } proc_response(mcl, cmd, len); } else if (cmd[0] & 0x01) proc_req[mcl->state](mcl, cmd, len); } static gboolean mdl_event_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct mcap_mdl *mdl = data; gboolean notify; DBG("Close MDL %d", mdl->mdlid); notify = (mdl->state == MDL_CONNECTED); shutdown_mdl(mdl); update_mcl_state(mdl->mcl); if (notify) { /*Callback to upper layer */ mdl->mcl->cb->mdl_closed(mdl, mdl->mcl->cb->user_data); } return FALSE; } static void mcap_connect_mdl_cb(GIOChannel *chan, GError *conn_err, gpointer data) { struct mcap_mdl_op_cb *con = data; struct mcap_mdl *mdl = con->mdl; mcap_mdl_operation_cb cb = con->cb.op; gpointer user_data = con->user_data; DBG("mdl connect callback"); if (conn_err) { DBG("ERROR: mdl connect callback"); mdl->state = MDL_CLOSED; g_io_channel_unref(mdl->dc); mdl->dc = NULL; cb(mdl, conn_err, user_data); return; } mdl->state = MDL_CONNECTED; mdl->wid = g_io_add_watch_full(mdl->dc, G_PRIORITY_DEFAULT, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) mdl_event_cb, mcap_mdl_ref(mdl), (GDestroyNotify) mcap_mdl_unref); cb(mdl, conn_err, user_data); } gboolean mcap_connect_mdl(struct mcap_mdl *mdl, uint8_t mode, uint16_t dcpsm, mcap_mdl_operation_cb connect_cb, gpointer user_data, GDestroyNotify destroy, GError **err) { struct mcap_mdl_op_cb *con; if (mdl->state != MDL_WAITING) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_MDL, "%s", error2str(MCAP_INVALID_MDL)); return FALSE; } if ((mode != L2CAP_MODE_ERTM) && (mode != L2CAP_MODE_STREAMING)) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, "Invalid MDL configuration"); return FALSE; } con = g_new0(struct mcap_mdl_op_cb, 1); con->mdl = mcap_mdl_ref(mdl); con->cb.op = connect_cb; con->destroy = destroy; con->user_data = user_data; mdl->dc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mdl_cb, con, (GDestroyNotify) free_mcap_mdl_op, err, BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->mi->src, BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr, BT_IO_OPT_PSM, dcpsm, BT_IO_OPT_MTU, MCAP_DC_MTU, BT_IO_OPT_SEC_LEVEL, mdl->mcl->mi->sec, BT_IO_OPT_MODE, mode, BT_IO_OPT_INVALID); if (!mdl->dc) { DBG("MDL Connection error"); mdl->state = MDL_CLOSED; mcap_mdl_unref(con->mdl); g_free(con); return FALSE; } return TRUE; } static gboolean mcl_control_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { GError *gerr = NULL; struct mcap_mcl *mcl = data; int sk, len; uint8_t buf[MCAP_CC_MTU]; if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) goto fail; sk = g_io_channel_unix_get_fd(chan); len = read(sk, buf, sizeof(buf)); if (len < 0) goto fail; proc_cmd(mcl, buf, (uint32_t) len); return TRUE; fail: if (mcl->state != MCL_IDLE) { if (mcl->req == MCL_WAITING_RSP) { /* notify error in pending callback */ g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_MCL_CLOSED, "MCL closed"); mcap_notify_error(mcl, gerr); g_error_free(gerr); } mcl->mi->mcl_disconnected_cb(mcl, mcl->mi->user_data); } mcap_cache_mcl(mcl); return FALSE; } static void mcap_connect_mcl_cb(GIOChannel *chan, GError *conn_err, gpointer user_data) { char dstaddr[18]; struct connect_mcl *con = user_data; struct mcap_mcl *aux, *mcl = con->mcl; mcap_mcl_connect_cb connect_cb = con->connect_cb; gpointer data = con->user_data; GError *gerr = NULL; mcl->ctrl &= ~MCAP_CTRL_CONN; if (conn_err) { if (mcl->ctrl & MCAP_CTRL_FREE) { mcap_mcl_release(mcl); mcl->mi->mcl_uncached_cb(mcl, mcl->mi->user_data); } connect_cb(NULL, conn_err, data); return; } ba2str(&mcl->addr, dstaddr); aux = find_mcl(mcl->mi->mcls, &mcl->addr); if (aux) { /* Double MCL connection case */ error("MCL error: Device %s is already connected", dstaddr); g_set_error(&gerr, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS, "MCL %s is already connected", dstaddr); connect_cb(NULL, gerr, data); g_error_free(gerr); return; } mcl->state = MCL_CONNECTED; mcl->role = MCL_INITIATOR; mcl->req = MCL_AVAILABLE; mcl->ctrl |= MCAP_CTRL_STD_OP; mcap_sync_init(mcl); if (mcl->ctrl & MCAP_CTRL_CACHED) mcap_uncache_mcl(mcl); else { mcl->ctrl &= ~MCAP_CTRL_FREE; mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls, mcap_mcl_ref(mcl)); } mcl->wid = g_io_add_watch_full(mcl->cc, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) mcl_control_cb, mcap_mcl_ref(mcl), (GDestroyNotify) mcap_mcl_unref); connect_cb(mcl, gerr, data); } static void set_mdl_properties(GIOChannel *chan, struct mcap_mdl *mdl) { struct mcap_mcl *mcl = mdl->mcl; mdl->state = MDL_CONNECTED; mdl->dc = g_io_channel_ref(chan); mdl->wid = g_io_add_watch_full(mdl->dc, G_PRIORITY_DEFAULT, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) mdl_event_cb, mcap_mdl_ref(mdl), (GDestroyNotify) mcap_mdl_unref); mcl->state = MCL_ACTIVE; mcl->cb->mdl_connected(mdl, mcl->cb->user_data); } static void mcl_io_destroy(gpointer data) { struct connect_mcl *con = data; mcap_mcl_unref(con->mcl); if (con->destroy) con->destroy(con->user_data); g_free(con); } gboolean mcap_create_mcl(struct mcap_instance *mi, const bdaddr_t *addr, uint16_t ccpsm, mcap_mcl_connect_cb connect_cb, gpointer user_data, GDestroyNotify destroy, GError **err) { struct mcap_mcl *mcl; struct connect_mcl *con; mcl = find_mcl(mi->mcls, addr); if (mcl) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_ALREADY_EXISTS, "MCL is already connected."); return FALSE; } mcl = find_mcl(mi->cached, addr); if (!mcl) { mcl = g_new0(struct mcap_mcl, 1); mcl->mi = mcap_instance_ref(mi); mcl->state = MCL_IDLE; bacpy(&mcl->addr, addr); set_default_cb(mcl); mcl->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1; } mcl->ctrl |= MCAP_CTRL_CONN; con = g_new0(struct connect_mcl, 1); con->mcl = mcap_mcl_ref(mcl); con->connect_cb = connect_cb; con->destroy = destroy; con->user_data = user_data; mcl->cc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mcl_cb, con, mcl_io_destroy, err, BT_IO_OPT_SOURCE_BDADDR, &mi->src, BT_IO_OPT_DEST_BDADDR, addr, BT_IO_OPT_PSM, ccpsm, BT_IO_OPT_MTU, MCAP_CC_MTU, BT_IO_OPT_SEC_LEVEL, mi->sec, BT_IO_OPT_MODE, L2CAP_MODE_ERTM, BT_IO_OPT_INVALID); if (!mcl->cc) { mcl->ctrl &= ~MCAP_CTRL_CONN; if (mcl->ctrl & MCAP_CTRL_FREE) { mcap_mcl_release(mcl); mcl->mi->mcl_uncached_cb(mcl, mcl->mi->user_data); } mcap_mcl_unref(con->mcl); g_free(con); return FALSE; } return TRUE; } static void connect_dc_event_cb(GIOChannel *chan, GError *gerr, gpointer user_data) { struct mcap_instance *mi = user_data; struct mcap_mcl *mcl; struct mcap_mdl *mdl; GError *err = NULL; bdaddr_t dst; GSList *l; if (gerr) return; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } mcl = find_mcl(mi->mcls, &dst); if (!mcl || mcl->state != MCL_PENDING) goto drop; for (l = mcl->mdls; l; l = l->next) { mdl = l->data; if (mdl->state == MDL_WAITING) { set_mdl_properties(chan, mdl); return; } } drop: g_io_channel_shutdown(chan, TRUE, NULL); } static void set_mcl_conf(GIOChannel *chan, struct mcap_mcl *mcl) { gboolean reconn; mcl->state = MCL_CONNECTED; mcl->role = MCL_ACCEPTOR; mcl->req = MCL_AVAILABLE; mcl->cc = g_io_channel_ref(chan); mcl->ctrl |= MCAP_CTRL_STD_OP; mcap_sync_init(mcl); reconn = (mcl->ctrl & MCAP_CTRL_CACHED); if (reconn) mcap_uncache_mcl(mcl); else mcl->mi->mcls = g_slist_prepend(mcl->mi->mcls, mcap_mcl_ref(mcl)); mcl->wid = g_io_add_watch_full(mcl->cc, G_PRIORITY_DEFAULT, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) mcl_control_cb, mcap_mcl_ref(mcl), (GDestroyNotify) mcap_mcl_unref); /* Callback to report new MCL */ if (reconn) mcl->mi->mcl_reconnected_cb(mcl, mcl->mi->user_data); else mcl->mi->mcl_connected_cb(mcl, mcl->mi->user_data); } static void connect_mcl_event_cb(GIOChannel *chan, GError *gerr, gpointer user_data) { struct mcap_instance *mi = user_data; struct mcap_mcl *mcl; bdaddr_t dst; char address[18], srcstr[18]; GError *err = NULL; if (gerr) return; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } ba2str(&mi->src, srcstr); mcl = find_mcl(mi->mcls, &dst); if (mcl) { error("Control channel already created with %s on adapter %s", address, srcstr); goto drop; } mcl = find_mcl(mi->cached, &dst); if (!mcl) { mcl = g_new0(struct mcap_mcl, 1); mcl->mi = mcap_instance_ref(mi); bacpy(&mcl->addr, &dst); set_default_cb(mcl); mcl->next_mdl = (rand() % MCAP_MDLID_FINAL) + 1; } set_mcl_conf(chan, mcl); return; drop: g_io_channel_shutdown(chan, TRUE, NULL); } struct mcap_instance *mcap_create_instance(bdaddr_t *src, BtIOSecLevel sec, uint16_t ccpsm, uint16_t dcpsm, mcap_mcl_event_cb mcl_connected, mcap_mcl_event_cb mcl_reconnected, mcap_mcl_event_cb mcl_disconnected, mcap_mcl_event_cb mcl_uncached, mcap_info_ind_event_cb mcl_sync_info_ind, gpointer user_data, GError **gerr) { struct mcap_instance *mi; if (sec < BT_IO_SEC_MEDIUM) { g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, "Security level can't be minor of %d", BT_IO_SEC_MEDIUM); return NULL; } if (!(mcl_connected && mcl_reconnected && mcl_disconnected && mcl_uncached)) { g_set_error(gerr, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, "The callbacks can't be null"); return NULL; } mi = g_new0(struct mcap_instance, 1); bacpy(&mi->src, src); mi->sec = sec; mi->mcl_connected_cb = mcl_connected; mi->mcl_reconnected_cb = mcl_reconnected; mi->mcl_disconnected_cb = mcl_disconnected; mi->mcl_uncached_cb = mcl_uncached; mi->mcl_sync_infoind_cb = mcl_sync_info_ind; mi->user_data = user_data; mi->csp_enabled = FALSE; /* Listen incoming connections in control channel */ mi->ccio = bt_io_listen(BT_IO_L2CAP, connect_mcl_event_cb, NULL, mi, NULL, gerr, BT_IO_OPT_SOURCE_BDADDR, &mi->src, BT_IO_OPT_PSM, ccpsm, BT_IO_OPT_MTU, MCAP_CC_MTU, BT_IO_OPT_SEC_LEVEL, sec, BT_IO_OPT_MODE, L2CAP_MODE_ERTM, BT_IO_OPT_INVALID); if (!mi->ccio) { error("%s", (*gerr)->message); g_free(mi); return NULL; } /* Listen incoming connections in data channels */ mi->dcio = bt_io_listen(BT_IO_L2CAP, connect_dc_event_cb, NULL, mi, NULL, gerr, BT_IO_OPT_SOURCE_BDADDR, &mi->src, BT_IO_OPT_PSM, dcpsm, BT_IO_OPT_MTU, MCAP_DC_MTU, BT_IO_OPT_SEC_LEVEL, sec, BT_IO_OPT_INVALID); if (!mi->dcio) { g_io_channel_shutdown(mi->ccio, TRUE, NULL); g_io_channel_unref(mi->ccio); mi->ccio = NULL; error("%s", (*gerr)->message); g_free(mi); return NULL; } /* Initialize random seed to generate mdlids for this instance */ srand(time(NULL)); return mcap_instance_ref(mi); } void mcap_release_instance(struct mcap_instance *mi) { GSList *l; if (!mi) return; if (mi->ccio) { g_io_channel_shutdown(mi->ccio, TRUE, NULL); g_io_channel_unref(mi->ccio); mi->ccio = NULL; } if (mi->dcio) { g_io_channel_shutdown(mi->dcio, TRUE, NULL); g_io_channel_unref(mi->dcio); mi->dcio = NULL; } for (l = mi->mcls; l; l = l->next) { mcap_mcl_release(l->data); mcap_mcl_unref(l->data); } g_slist_free(mi->mcls); mi->mcls = NULL; for (l = mi->cached; l; l = l->next) { mcap_mcl_release(l->data); mcap_mcl_unref(l->data); } g_slist_free(mi->cached); mi->cached = NULL; } struct mcap_instance *mcap_instance_ref(struct mcap_instance *mi) { mi->ref++; DBG("mcap_instance_ref(%p): ref=%d", mi, mi->ref); return mi; } void mcap_instance_unref(struct mcap_instance *mi) { mi->ref--; DBG("mcap_instance_unref(%p): ref=%d", mi, mi->ref); if (mi->ref > 0) return; mcap_release_instance(mi); g_free(mi); } uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err) { uint16_t lpsm; if (!(mi && mi->ccio)) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, "Invalid MCAP instance"); return 0; } if (!bt_io_get(mi->ccio, BT_IO_L2CAP, err, BT_IO_OPT_PSM, &lpsm, BT_IO_OPT_INVALID)) return 0; return lpsm; } uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err) { uint16_t lpsm; if (!(mi && mi->dcio)) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, "Invalid MCAP instance"); return 0; } if (!bt_io_get(mi->dcio, BT_IO_L2CAP, err, BT_IO_OPT_PSM, &lpsm, BT_IO_OPT_INVALID)) return 0; return lpsm; } gboolean mcap_set_data_chan_mode(struct mcap_instance *mi, uint8_t mode, GError **err) { if (!(mi && mi->dcio)) { g_set_error(err, MCAP_ERROR, MCAP_ERROR_INVALID_ARGS, "Invalid MCAP instance"); return FALSE; } return bt_io_set(mi->dcio, BT_IO_L2CAP, err, BT_IO_OPT_MODE, mode, BT_IO_OPT_INVALID); } struct mcap_mdl *mcap_mdl_ref(struct mcap_mdl *mdl) { mdl->ref++; DBG("mcap_mdl_ref(%p): ref=%d", mdl, mdl->ref); return mdl; } void mcap_mdl_unref(struct mcap_mdl *mdl) { mdl->ref--; DBG("mcap_mdl_unref(%p): ref=%d", mdl, mdl->ref); if (mdl->ref > 0) return; free_mdl(mdl); } bluez-4.101/health/hdp_manager.h0000644000000000000000000000164511766125764013437 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int hdp_manager_init(DBusConnection *conn); void hdp_manager_exit(void); bluez-4.101/health/mcap_lib.h0000644000000000000000000001476011766125764012742 00000000000000/* * * MCAP for BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __MCAP_LIB_H #define __MCAP_LIB_H #ifdef __cplusplus extern "C" { #endif typedef enum { /* MCAP Error Response Codes */ MCAP_ERROR_INVALID_OP_CODE = 1, MCAP_ERROR_INVALID_PARAM_VALUE, MCAP_ERROR_INVALID_MDEP, MCAP_ERROR_MDEP_BUSY, MCAP_ERROR_INVALID_MDL, MCAP_ERROR_MDL_BUSY, MCAP_ERROR_INVALID_OPERATION, MCAP_ERROR_RESOURCE_UNAVAILABLE, MCAP_ERROR_UNSPECIFIED_ERROR, MCAP_ERROR_REQUEST_NOT_SUPPORTED, MCAP_ERROR_CONFIGURATION_REJECTED, /* MCAP Internal Errors */ MCAP_ERROR_INVALID_ARGS, MCAP_ERROR_ALREADY_EXISTS, MCAP_ERROR_REQ_IGNORED, MCAP_ERROR_MCL_CLOSED, MCAP_ERROR_FAILED } McapError; typedef enum { MCAP_MDL_CB_INVALID, MCAP_MDL_CB_CONNECTED, /* mcap_mdl_event_cb */ MCAP_MDL_CB_CLOSED, /* mcap_mdl_event_cb */ MCAP_MDL_CB_DELETED, /* mcap_mdl_event_cb */ MCAP_MDL_CB_ABORTED, /* mcap_mdl_event_cb */ MCAP_MDL_CB_REMOTE_CONN_REQ, /* mcap_remote_mdl_conn_req_cb */ MCAP_MDL_CB_REMOTE_RECONN_REQ /* mcap_remote_mdl_reconn_req_cb */ } McapMclCb; struct mcap_instance; struct mcap_mcl; struct mcap_mdl; struct sync_info_ind_data; /************ Callbacks ************/ /* MDL callbacks */ typedef void (* mcap_mdl_event_cb) (struct mcap_mdl *mdl, gpointer data); typedef void (* mcap_mdl_operation_conf_cb) (struct mcap_mdl *mdl, uint8_t conf, GError *err, gpointer data); typedef void (* mcap_mdl_operation_cb) (struct mcap_mdl *mdl, GError *err, gpointer data); typedef void (* mcap_mdl_notify_cb) (GError *err, gpointer data); /* Next function should return an MCAP appropriate response code */ typedef uint8_t (* mcap_remote_mdl_conn_req_cb) (struct mcap_mcl *mcl, uint8_t mdepid, uint16_t mdlid, uint8_t *conf, gpointer data); typedef uint8_t (* mcap_remote_mdl_reconn_req_cb) (struct mcap_mdl *mdl, gpointer data); /* MCL callbacks */ typedef void (* mcap_mcl_event_cb) (struct mcap_mcl *mcl, gpointer data); typedef void (* mcap_mcl_connect_cb) (struct mcap_mcl *mcl, GError *err, gpointer data); /* CSP callbacks */ typedef void (* mcap_info_ind_event_cb) (struct mcap_mcl *mcl, struct sync_info_ind_data *data); typedef void (* mcap_sync_cap_cb) (struct mcap_mcl *mcl, uint8_t mcap_err, uint8_t btclockres, uint16_t synclead, uint16_t tmstampres, uint16_t tmstampacc, GError *err, gpointer data); typedef void (* mcap_sync_set_cb) (struct mcap_mcl *mcl, uint8_t mcap_err, uint32_t btclock, uint64_t timestamp, uint16_t accuracy, GError *err, gpointer data); /************ Operations ************/ /* MDL operations */ gboolean mcap_create_mdl(struct mcap_mcl *mcl, uint8_t mdepid, uint8_t conf, mcap_mdl_operation_conf_cb connect_cb, gpointer user_data, GDestroyNotify destroy, GError **err); gboolean mcap_reconnect_mdl(struct mcap_mdl *mdl, mcap_mdl_operation_cb reconnect_cb, gpointer user_data, GDestroyNotify destroy, GError **err); gboolean mcap_delete_all_mdls(struct mcap_mcl *mcl, mcap_mdl_notify_cb delete_cb, gpointer user_data, GDestroyNotify destroy, GError **err); gboolean mcap_delete_mdl(struct mcap_mdl *mdl, mcap_mdl_notify_cb delete_cb, gpointer user_data, GDestroyNotify destroy, GError **err); gboolean mcap_connect_mdl(struct mcap_mdl *mdl, uint8_t mode, uint16_t dcpsm, mcap_mdl_operation_cb connect_cb, gpointer user_data, GDestroyNotify destroy, GError **err); gboolean mcap_mdl_abort(struct mcap_mdl *mdl, mcap_mdl_notify_cb abort_cb, gpointer user_data, GDestroyNotify destroy, GError **err); int mcap_mdl_get_fd(struct mcap_mdl *mdl); uint16_t mcap_mdl_get_mdlid(struct mcap_mdl *mdl); struct mcap_mdl *mcap_mdl_ref(struct mcap_mdl *mdl); void mcap_mdl_unref(struct mcap_mdl *mdl); /* MCL operations */ gboolean mcap_create_mcl(struct mcap_instance *mi, const bdaddr_t *addr, uint16_t ccpsm, mcap_mcl_connect_cb connect_cb, gpointer user_data, GDestroyNotify destroy, GError **err); void mcap_close_mcl(struct mcap_mcl *mcl, gboolean cache); gboolean mcap_mcl_set_cb(struct mcap_mcl *mcl, gpointer user_data, GError **gerr, McapMclCb cb1, ...); void mcap_mcl_get_addr(struct mcap_mcl *mcl, bdaddr_t *addr); struct mcap_mcl *mcap_mcl_ref(struct mcap_mcl *mcl); void mcap_mcl_unref(struct mcap_mcl *mcl); /* CSP operations */ void mcap_enable_csp(struct mcap_instance *mi); void mcap_disable_csp(struct mcap_instance *mi); uint64_t mcap_get_timestamp(struct mcap_mcl *mcl, struct timespec *given_time); uint32_t mcap_get_btclock(struct mcap_mcl *mcl); void mcap_sync_cap_req(struct mcap_mcl *mcl, uint16_t reqacc, mcap_sync_cap_cb cb, gpointer user_data, GError **err); void mcap_sync_set_req(struct mcap_mcl *mcl, uint8_t update, uint32_t btclock, uint64_t timestamp, mcap_sync_set_cb cb, gpointer user_data, GError **err); /* MCAP main operations */ struct mcap_instance *mcap_create_instance(bdaddr_t *src, BtIOSecLevel sec, uint16_t ccpsm, uint16_t dcpsm, mcap_mcl_event_cb mcl_connected, mcap_mcl_event_cb mcl_reconnected, mcap_mcl_event_cb mcl_disconnected, mcap_mcl_event_cb mcl_uncached, mcap_info_ind_event_cb mcl_sync_info_ind, gpointer user_data, GError **gerr); void mcap_release_instance(struct mcap_instance *mi); struct mcap_instance *mcap_instance_ref(struct mcap_instance *mi); void mcap_instance_unref(struct mcap_instance *mi); uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err); uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err); gboolean mcap_set_data_chan_mode(struct mcap_instance *mi, uint8_t mode, GError **err); #ifdef __cplusplus } #endif #endif /* __MCAP_LIB_H */ bluez-4.101/health/hdp.c0000644000000000000000000015044011766125764011736 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mcap_lib.h" #include "hdp_types.h" #include "hdp_util.h" #include "hdp.h" #include "mcap.h" #define ECHO_TIMEOUT 1 /* second */ #define HDP_ECHO_LEN 15 static DBusConnection *connection = NULL; static GSList *applications = NULL; static GSList *devices = NULL; static uint8_t next_app_id = HDP_MDEP_INITIAL; static GSList *adapters; static gboolean update_adapter(struct hdp_adapter *adapter); static struct hdp_device *create_health_device(DBusConnection *conn, struct btd_device *device); static void free_echo_data(struct hdp_echo_data *edata); struct hdp_create_dc { DBusConnection *conn; DBusMessage *msg; struct hdp_application *app; struct hdp_device *dev; uint8_t config; uint8_t mdep; guint ref; mcap_mdl_operation_cb cb; }; struct hdp_tmp_dc_data { DBusConnection *conn; DBusMessage *msg; struct hdp_channel *hdp_chann; guint ref; mcap_mdl_operation_cb cb; }; struct hdp_echo_data { gboolean echo_done; /* Is a echo was already done */ gpointer buf; /* echo packet sent */ uint tid; /* echo timeout */ }; static struct hdp_channel *hdp_channel_ref(struct hdp_channel *chan) { if (chan == NULL) return NULL; chan->ref++; DBG("health_channel_ref(%p): ref=%d", chan, chan->ref); return chan; } static void free_health_channel(struct hdp_channel *chan) { if (chan->mdep == HDP_MDEP_ECHO) { free_echo_data(chan->edata); chan->edata = NULL; } mcap_mdl_unref(chan->mdl); hdp_application_unref(chan->app); health_device_unref(chan->dev); g_free(chan->path); g_free(chan); } static void hdp_channel_unref(struct hdp_channel *chan) { if (chan == NULL) return; chan->ref --; DBG("health_channel_unref(%p): ref=%d", chan, chan->ref); if (chan->ref > 0) return; free_health_channel(chan); } static void free_hdp_create_dc(struct hdp_create_dc *dc_data) { dbus_message_unref(dc_data->msg); dbus_connection_unref(dc_data->conn); hdp_application_unref(dc_data->app); health_device_unref(dc_data->dev); g_free(dc_data); } static struct hdp_create_dc *hdp_create_data_ref(struct hdp_create_dc *dc_data) { dc_data->ref++; DBG("hdp_create_data_ref(%p): ref=%d", dc_data, dc_data->ref); return dc_data; } static void hdp_create_data_unref(struct hdp_create_dc *dc_data) { dc_data->ref--; DBG("hdp_create_data_unref(%p): ref=%d", dc_data, dc_data->ref); if (dc_data->ref > 0) return; free_hdp_create_dc(dc_data); } static void free_hdp_conn_dc(struct hdp_tmp_dc_data *data) { dbus_message_unref(data->msg); dbus_connection_unref(data->conn); hdp_channel_unref(data->hdp_chann); g_free(data); } static struct hdp_tmp_dc_data *hdp_tmp_dc_data_ref(struct hdp_tmp_dc_data *data) { data->ref++; DBG("hdp_conn_data_ref(%p): ref=%d", data, data->ref); return data; } static void hdp_tmp_dc_data_unref(struct hdp_tmp_dc_data *data) { data->ref--; DBG("hdp_conn_data_unref(%p): ref=%d", data, data->ref); if (data->ref > 0) return; free_hdp_conn_dc(data); } static int cmp_app_id(gconstpointer a, gconstpointer b) { const struct hdp_application *app = a; const uint8_t *id = b; return app->id - *id; } static int cmp_adapter(gconstpointer a, gconstpointer b) { const struct hdp_adapter *hdp_adapter = a; const struct btd_adapter *adapter = b; if (hdp_adapter->btd_adapter == adapter) return 0; return -1; } static int cmp_device(gconstpointer a, gconstpointer b) { const struct hdp_device *hdp_device = a; const struct btd_device *device = b; if (hdp_device->dev == device) return 0; return -1; } static gint cmp_dev_addr(gconstpointer a, gconstpointer dst) { const struct hdp_device *device = a; bdaddr_t addr; device_get_address(device->dev, &addr, NULL); return bacmp(&addr, dst); } static gint cmp_dev_mcl(gconstpointer a, gconstpointer mcl) { const struct hdp_device *device = a; if (mcl == device->mcl) return 0; return -1; } static gint cmp_chan_mdlid(gconstpointer a, gconstpointer b) { const struct hdp_channel *chan = a; const uint16_t *mdlid = b; return chan->mdlid - *mdlid; } static gint cmp_chan_path(gconstpointer a, gconstpointer b) { const struct hdp_channel *chan = a; const char *path = b; return g_ascii_strcasecmp(chan->path, path); } static gint cmp_chan_mdl(gconstpointer a, gconstpointer mdl) { const struct hdp_channel *chan = a; if (chan->mdl == mdl) return 0; return -1; } static uint8_t get_app_id(void) { uint8_t id = next_app_id; do { GSList *l = g_slist_find_custom(applications, &id, cmp_app_id); if (l == NULL) { next_app_id = (id % HDP_MDEP_FINAL) + 1; return id; } else id = (id % HDP_MDEP_FINAL) + 1; } while (id != next_app_id); /* No more ids available */ return 0; } static int cmp_app(gconstpointer a, gconstpointer b) { const struct hdp_application *app = a; return g_strcmp0(app->path, b); } static gboolean set_app_path(struct hdp_application *app) { app->id = get_app_id(); if (app->id == 0) return FALSE; app->path = g_strdup_printf(MANAGER_PATH "/health_app_%d", app->id); return TRUE; }; static void device_unref_mcl(struct hdp_device *hdp_device) { if (hdp_device->mcl == NULL) return; mcap_close_mcl(hdp_device->mcl, FALSE); mcap_mcl_unref(hdp_device->mcl); hdp_device->mcl = NULL; hdp_device->mcl_conn = FALSE; } static void free_health_device(struct hdp_device *device) { if (device->conn != NULL) { dbus_connection_unref(device->conn); device->conn = NULL; } if (device->dev != NULL) { btd_device_unref(device->dev); device->dev = NULL; } device_unref_mcl(device); g_free(device); } static void remove_application(struct hdp_application *app) { DBG("Application %s deleted", app->path); hdp_application_unref(app); g_slist_foreach(adapters, (GFunc) update_adapter, NULL); } static void client_disconnected(DBusConnection *conn, void *user_data) { struct hdp_application *app = user_data; DBG("Client disconnected from the bus, deleting hdp application"); applications = g_slist_remove(applications, app); app->dbus_watcher = 0; /* Watcher shouldn't be freed in this case */ remove_application(app); } static DBusMessage *manager_create_application(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct hdp_application *app; const char *name; DBusMessageIter iter; GError *err = NULL; dbus_message_iter_init(msg, &iter); app = hdp_get_app_config(&iter, &err); if (err != NULL) { g_error_free(err); return btd_error_invalid_args(msg); } name = dbus_message_get_sender(msg); if (name == NULL) { hdp_application_unref(app); return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError", "Can't get sender name"); } if (!set_app_path(app)) { hdp_application_unref(app); return g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError", "Can't get a valid id for the application"); } app->oname = g_strdup(name); app->conn = dbus_connection_ref(conn); applications = g_slist_prepend(applications, app); app->dbus_watcher = g_dbus_add_disconnect_watch(conn, name, client_disconnected, app, NULL); g_slist_foreach(adapters, (GFunc) update_adapter, NULL); DBG("Health application created with id %s", app->path); return g_dbus_create_reply(msg, DBUS_TYPE_OBJECT_PATH, &app->path, DBUS_TYPE_INVALID); } static DBusMessage *manager_destroy_application(DBusConnection *conn, DBusMessage *msg, void *user_data) { const char *path; struct hdp_application *app; GSList *l; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); l = g_slist_find_custom(applications, path, cmp_app); if (l == NULL) return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments", "Invalid arguments in method call, " "no such application"); app = l->data; applications = g_slist_remove(applications, app); remove_application(app); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static void manager_path_unregister(gpointer data) { g_slist_foreach(applications, (GFunc) hdp_application_unref, NULL); g_slist_free(applications); applications = NULL; g_slist_foreach(adapters, (GFunc) update_adapter, NULL); } static const GDBusMethodTable health_manager_methods[] = { { GDBUS_METHOD("CreateApplication", GDBUS_ARGS({ "config", "a{sv}" }), GDBUS_ARGS({ "application", "o" }), manager_create_application) }, { GDBUS_METHOD("DestroyApplication", GDBUS_ARGS({ "application", "o" }), NULL, manager_destroy_application) }, { } }; static DBusMessage *channel_get_properties(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct hdp_channel *chan = user_data; DBusMessageIter iter, dict; DBusMessage *reply; const char *path; char *type; reply = dbus_message_new_method_return(msg); if (reply == NULL) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); path = device_get_path(chan->dev->dev); dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH, &path); path = chan->app->path; dict_append_entry(&dict, "Application", DBUS_TYPE_OBJECT_PATH, &path); if (chan->config == HDP_RELIABLE_DC) type = g_strdup("Reliable"); else type = g_strdup("Streaming"); dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &type); g_free(type); dbus_message_iter_close_container(&iter, &dict); return reply; } static void hdp_tmp_dc_data_destroy(gpointer data) { struct hdp_tmp_dc_data *hdp_conn = data; hdp_tmp_dc_data_unref(hdp_conn); } static void abort_mdl_cb(GError *err, gpointer data) { if (err != NULL) error("Aborting error: %s", err->message); } static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data) { struct hdp_tmp_dc_data *dc_data = data; DBusMessage *reply; int fd; if (err != NULL) { struct hdp_channel *chan = dc_data->hdp_chann; GError *gerr = NULL; error("%s", err->message); reply = g_dbus_create_error(dc_data->msg, ERROR_INTERFACE ".HealthError", "Cannot reconnect: %s", err->message); g_dbus_send_message(dc_data->conn, reply); /* Send abort request because remote side */ /* is now in PENDING state */ if (!mcap_mdl_abort(chan->mdl, abort_mdl_cb, NULL, NULL, &gerr)) { error("%s", gerr->message); g_error_free(gerr); } return; } fd = mcap_mdl_get_fd(dc_data->hdp_chann->mdl); if (fd < 0) { reply = g_dbus_create_error(dc_data->msg, ERROR_INTERFACE ".HealthError", "Cannot get file descriptor"); g_dbus_send_message(dc_data->conn, reply); return; } reply = g_dbus_create_reply(dc_data->msg, DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_INVALID); g_dbus_send_message(dc_data->conn, reply); g_dbus_emit_signal(dc_data->conn, device_get_path(dc_data->hdp_chann->dev->dev), HEALTH_DEVICE, "ChannelConnected", DBUS_TYPE_OBJECT_PATH, &dc_data->hdp_chann->path, DBUS_TYPE_INVALID); } static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err) { struct hdp_tmp_dc_data *hdp_conn = user_data; struct hdp_channel *hdp_chann = hdp_conn->hdp_chann; GError *gerr = NULL; uint8_t mode; if (err != NULL) { hdp_conn->cb(hdp_chann->mdl, err, hdp_conn); return; } if (hdp_chann->config == HDP_RELIABLE_DC) mode = L2CAP_MODE_ERTM; else mode = L2CAP_MODE_STREAMING; if (mcap_connect_mdl(hdp_chann->mdl, mode, dcpsm, hdp_conn->cb, hdp_tmp_dc_data_ref(hdp_conn), hdp_tmp_dc_data_destroy, &gerr)) return; hdp_tmp_dc_data_unref(hdp_conn); hdp_conn->cb(hdp_chann->mdl, err, hdp_conn); g_error_free(gerr); } static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err, gpointer data) { struct hdp_tmp_dc_data *dc_data = data; GError *gerr = NULL; DBusMessage *reply; if (err != NULL) { reply = g_dbus_create_error(dc_data->msg, ERROR_INTERFACE ".HealthError", "Cannot reconnect: %s", err->message); g_dbus_send_message(dc_data->conn, reply); return; } dc_data->cb = hdp_mdl_reconn_cb; if (hdp_get_dcpsm(dc_data->hdp_chann->dev, hdp_get_dcpsm_cb, hdp_tmp_dc_data_ref(dc_data), hdp_tmp_dc_data_destroy, &gerr)) return; error("%s", gerr->message); reply = g_dbus_create_error(dc_data->msg, ERROR_INTERFACE ".HealthError", "Cannot reconnect: %s", gerr->message); g_dbus_send_message(dc_data->conn, reply); hdp_tmp_dc_data_unref(dc_data); g_error_free(gerr); /* Send abort request because remote side is now in PENDING state */ if (!mcap_mdl_abort(mdl, abort_mdl_cb, NULL, NULL, &gerr)) { error("%s", gerr->message); g_error_free(gerr); } } static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data, GError *err) { DBusMessage *reply; GError *gerr = NULL; int fd; if (err != NULL) { return g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError", "%s", err->message); } fd = mcap_mdl_get_fd(data->hdp_chann->mdl); if (fd >= 0) return g_dbus_create_reply(data->msg, DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_INVALID); hdp_tmp_dc_data_ref(data); if (mcap_reconnect_mdl(data->hdp_chann->mdl, device_reconnect_mdl_cb, data, hdp_tmp_dc_data_destroy, &gerr)) return NULL; hdp_tmp_dc_data_unref(data); reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError", "Cannot reconnect: %s", gerr->message); g_error_free(gerr); return reply; } static void channel_acquire_cb(gpointer data, GError *err) { struct hdp_tmp_dc_data *dc_data = data; DBusMessage *reply; reply = channel_acquire_continue(data, err); if (reply != NULL) g_dbus_send_message(dc_data->conn, reply); } static DBusMessage *channel_acquire(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct hdp_channel *chan = user_data; struct hdp_tmp_dc_data *dc_data; GError *gerr = NULL; DBusMessage *reply; dc_data = g_new0(struct hdp_tmp_dc_data, 1); dc_data->conn = dbus_connection_ref(conn); dc_data->msg = dbus_message_ref(msg); dc_data->hdp_chann = hdp_channel_ref(chan); if (chan->dev->mcl_conn) { reply = channel_acquire_continue(hdp_tmp_dc_data_ref(dc_data), NULL); hdp_tmp_dc_data_unref(dc_data); return reply; } if (hdp_establish_mcl(chan->dev, channel_acquire_cb, hdp_tmp_dc_data_ref(dc_data), hdp_tmp_dc_data_destroy, &gerr)) return NULL; reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError", "%s", gerr->message); hdp_tmp_dc_data_unref(dc_data); g_error_free(gerr); return reply; } static void close_mdl(struct hdp_channel *hdp_chann) { int fd; fd = mcap_mdl_get_fd(hdp_chann->mdl); if (fd < 0) return; close(fd); } static DBusMessage *channel_release(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct hdp_channel *hdp_chann = user_data; close_mdl(hdp_chann); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static void free_echo_data(struct hdp_echo_data *edata) { if (edata == NULL) return; if (edata->tid > 0) g_source_remove(edata->tid); if (edata->buf != NULL) g_free(edata->buf); g_free(edata); } static void health_channel_destroy(void *data) { struct hdp_channel *hdp_chan = data; struct hdp_device *dev = hdp_chan->dev; DBG("Destroy Health Channel %s", hdp_chan->path); if (g_slist_find(dev->channels, hdp_chan) == NULL) goto end; dev->channels = g_slist_remove(dev->channels, hdp_chan); if (hdp_chan->mdep != HDP_MDEP_ECHO) g_dbus_emit_signal(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE, "ChannelDeleted", DBUS_TYPE_OBJECT_PATH, &hdp_chan->path, DBUS_TYPE_INVALID); if (hdp_chan == dev->fr) { hdp_channel_unref(dev->fr); dev->fr = NULL; } end: hdp_channel_unref(hdp_chan); } static const GDBusMethodTable health_channels_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), channel_get_properties) }, { GDBUS_ASYNC_METHOD("Acquire", NULL, GDBUS_ARGS({ "fd", "h" }), channel_acquire) }, { GDBUS_METHOD("Release", NULL, NULL, channel_release) }, { } }; static struct hdp_channel *create_channel(struct hdp_device *dev, uint8_t config, struct mcap_mdl *mdl, uint16_t mdlid, struct hdp_application *app, GError **err) { struct hdp_channel *hdp_chann; if (dev == NULL) return NULL; hdp_chann = g_new0(struct hdp_channel, 1); hdp_chann->config = config; hdp_chann->dev = health_device_ref(dev); hdp_chann->mdlid = mdlid; if (mdl != NULL) hdp_chann->mdl = mcap_mdl_ref(mdl); if (app != NULL) { hdp_chann->mdep = app->id; hdp_chann->app = hdp_application_ref(app); } else hdp_chann->edata = g_new0(struct hdp_echo_data, 1); hdp_chann->path = g_strdup_printf("%s/chan%d", device_get_path(hdp_chann->dev->dev), hdp_chann->mdlid); dev->channels = g_slist_append(dev->channels, hdp_channel_ref(hdp_chann)); if (hdp_chann->mdep == HDP_MDEP_ECHO) return hdp_channel_ref(hdp_chann); if (!g_dbus_register_interface(dev->conn, hdp_chann->path, HEALTH_CHANNEL, health_channels_methods, NULL, NULL, hdp_chann, health_channel_destroy)) { g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR, "Can't register the channel interface"); health_channel_destroy(hdp_chann); return NULL; } return hdp_channel_ref(hdp_chann); } static void remove_channels(struct hdp_device *dev) { struct hdp_channel *chan; char *path; while (dev->channels != NULL) { chan = dev->channels->data; path = g_strdup(chan->path); if (!g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL)) health_channel_destroy(chan); g_free(path); } } static void close_device_con(struct hdp_device *dev, gboolean cache) { if (dev->mcl == NULL) return; mcap_close_mcl(dev->mcl, cache); dev->mcl_conn = FALSE; if (cache) return; device_unref_mcl(dev); remove_channels(dev); if (!dev->sdp_present) { const char *path; path = device_get_path(dev->dev); g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE); } } static int send_echo_data(int sock, const void *buf, uint32_t size) { const uint8_t *buf_b = buf; uint32_t sent = 0; while (sent < size) { int n = write(sock, buf_b + sent, size - sent); if (n < 0) return -1; sent += n; } return 0; } static gboolean serve_echo(GIOChannel *io_chan, GIOCondition cond, gpointer data) { struct hdp_channel *chan = data; uint8_t buf[MCAP_DC_MTU]; int fd, len; if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { hdp_channel_unref(chan); return FALSE; } if (chan->edata->echo_done) goto fail; chan->edata->echo_done = TRUE; fd = g_io_channel_unix_get_fd(io_chan); len = read(fd, buf, sizeof(buf)); if (send_echo_data(fd, buf, len) >= 0) return TRUE; fail: close_device_con(chan->dev, FALSE); hdp_channel_unref(chan); return FALSE; } static gboolean check_channel_conf(struct hdp_channel *chan) { GError *err = NULL; GIOChannel *io; uint8_t mode; uint16_t imtu, omtu; int fd; fd = mcap_mdl_get_fd(chan->mdl); if (fd < 0) return FALSE; io = g_io_channel_unix_new(fd); if (!bt_io_get(io, BT_IO_L2CAP, &err, BT_IO_OPT_MODE, &mode, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_INVALID)) { error("Error: %s", err->message); g_io_channel_unref(io); g_error_free(err); return FALSE; } g_io_channel_unref(io); switch (chan->config) { case HDP_RELIABLE_DC: if (mode != L2CAP_MODE_ERTM) return FALSE; break; case HDP_STREAMING_DC: if (mode != L2CAP_MODE_STREAMING) return FALSE; break; default: error("Error: Connected with unknown configuration"); return FALSE; } DBG("MDL imtu %d omtu %d Channel imtu %d omtu %d", imtu, omtu, chan->imtu, chan->omtu); if (chan->imtu == 0) chan->imtu = imtu; if (chan->omtu == 0) chan->omtu = omtu; if (chan->imtu != imtu || chan->omtu != omtu) return FALSE; return TRUE; } static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data) { struct hdp_device *dev = data; struct hdp_channel *chan; DBG("hdp_mcap_mdl_connected_cb"); if (dev->ndc == NULL) return; chan = dev->ndc; if (chan->mdl == NULL) chan->mdl = mcap_mdl_ref(mdl); if (g_slist_find(dev->channels, chan) == NULL) dev->channels = g_slist_prepend(dev->channels, hdp_channel_ref(chan)); if (!check_channel_conf(chan)) { close_mdl(chan); goto end; } if (chan->mdep == HDP_MDEP_ECHO) { GIOChannel *io; int fd; fd = mcap_mdl_get_fd(chan->mdl); if (fd < 0) goto end; chan->edata->echo_done = FALSE; io = g_io_channel_unix_new(fd); g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN, serve_echo, hdp_channel_ref(chan)); g_io_channel_unref(io); goto end; } g_dbus_emit_signal(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE, "ChannelConnected", DBUS_TYPE_OBJECT_PATH, &chan->path, DBUS_TYPE_INVALID); if (dev->fr != NULL) goto end; dev->fr = hdp_channel_ref(chan); emit_property_changed(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE, "MainChannel", DBUS_TYPE_OBJECT_PATH, &dev->fr->path); end: hdp_channel_unref(dev->ndc); dev->ndc = NULL; } static void hdp_mcap_mdl_closed_cb(struct mcap_mdl *mdl, void *data) { /* struct hdp_device *dev = data; */ DBG("hdp_mcap_mdl_closed_cb"); /* Nothing to do */ } static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data) { struct hdp_device *dev = data; struct hdp_channel *chan; char *path; GSList *l; DBG("hdp_mcap_mdl_deleted_cb"); l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl); if (l == NULL) return; chan = l->data; path = g_strdup(chan->path); if (!g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL)) health_channel_destroy(chan); g_free(path); } static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data) { struct hdp_device *dev = data; DBG("hdp_mcap_mdl_aborted_cb"); if (dev->ndc == NULL) return; dev->ndc->mdl = mcap_mdl_ref(mdl); if (g_slist_find(dev->channels, dev->ndc) == NULL) dev->channels = g_slist_prepend(dev->channels, hdp_channel_ref(dev->ndc)); if (dev->ndc->mdep != HDP_MDEP_ECHO) g_dbus_emit_signal(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE, "ChannelConnected", DBUS_TYPE_OBJECT_PATH, &dev->ndc->path, DBUS_TYPE_INVALID); hdp_channel_unref(dev->ndc); dev->ndc = NULL; } static uint8_t hdp2l2cap_mode(uint8_t hdp_mode) { return hdp_mode == HDP_STREAMING_DC ? L2CAP_MODE_STREAMING : L2CAP_MODE_ERTM; } static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid, uint16_t mdlid, uint8_t *conf, void *data) { struct hdp_device *dev = data; struct hdp_application *app; GError *err = NULL; GSList *l; DBG("Data channel request"); if (mdepid == HDP_MDEP_ECHO) { switch (*conf) { case HDP_NO_PREFERENCE_DC: *conf = HDP_RELIABLE_DC; case HDP_RELIABLE_DC: break; case HDP_STREAMING_DC: return MCAP_CONFIGURATION_REJECTED; default: /* Special case defined in HDP spec 3.4. When an invalid * configuration is received we shall close the MCL when * we are still processing the callback. */ close_device_con(dev, FALSE); return MCAP_CONFIGURATION_REJECTED; /* not processed */ } if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi, L2CAP_MODE_ERTM, &err)) { error("Error: %s", err->message); g_error_free(err); return MCAP_MDL_BUSY; } dev->ndc = create_channel(dev, *conf, NULL, mdlid, NULL, NULL); if (dev->ndc == NULL) return MCAP_MDL_BUSY; return MCAP_SUCCESS; } l = g_slist_find_custom(applications, &mdepid, cmp_app_id); if (l == NULL) return MCAP_INVALID_MDEP; app = l->data; /* Check if is the first dc if so, * only reliable configuration is allowed */ switch (*conf) { case HDP_NO_PREFERENCE_DC: if (app->role == HDP_SINK) return MCAP_CONFIGURATION_REJECTED; else if (dev->fr && app->chan_type_set) *conf = app->chan_type; else *conf = HDP_RELIABLE_DC; break; case HDP_STREAMING_DC: if (!dev->fr || app->role == HDP_SOURCE) return MCAP_CONFIGURATION_REJECTED; case HDP_RELIABLE_DC: if (app->role == HDP_SOURCE) return MCAP_CONFIGURATION_REJECTED; break; default: /* Special case defined in HDP spec 3.4. When an invalid * configuration is received we shall close the MCL when * we are still processing the callback. */ close_device_con(dev, FALSE); return MCAP_CONFIGURATION_REJECTED; /* not processed */ } l = g_slist_find_custom(dev->channels, &mdlid, cmp_chan_mdlid); if (l != NULL) { struct hdp_channel *chan = l->data; char *path; path = g_strdup(chan->path); g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL); g_free(path); } if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi, hdp2l2cap_mode(*conf), &err)) { error("Error: %s", err->message); g_error_free(err); return MCAP_MDL_BUSY; } dev->ndc = create_channel(dev, *conf, NULL, mdlid, app, NULL); if (dev->ndc == NULL) return MCAP_MDL_BUSY; return MCAP_SUCCESS; } static uint8_t hdp_mcap_mdl_reconn_req_cb(struct mcap_mdl *mdl, void *data) { struct hdp_device *dev = data; struct hdp_channel *chan; GError *err = NULL; GSList *l; l = g_slist_find_custom(dev->channels, mdl, cmp_chan_mdl); if (l == NULL) return MCAP_INVALID_MDL; chan = l->data; if (dev->fr == NULL && chan->config != HDP_RELIABLE_DC && chan->mdep != HDP_MDEP_ECHO) return MCAP_UNSPECIFIED_ERROR; if (!mcap_set_data_chan_mode(dev->hdp_adapter->mi, hdp2l2cap_mode(chan->config), &err)) { error("Error: %s", err->message); g_error_free(err); return MCAP_MDL_BUSY; } dev->ndc = hdp_channel_ref(chan); return MCAP_SUCCESS; } gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err) { gboolean ret; if (device->mcl == NULL) return FALSE; ret = mcap_mcl_set_cb(device->mcl, device, err, MCAP_MDL_CB_CONNECTED, hdp_mcap_mdl_connected_cb, MCAP_MDL_CB_CLOSED, hdp_mcap_mdl_closed_cb, MCAP_MDL_CB_DELETED, hdp_mcap_mdl_deleted_cb, MCAP_MDL_CB_ABORTED, hdp_mcap_mdl_aborted_cb, MCAP_MDL_CB_REMOTE_CONN_REQ, hdp_mcap_mdl_conn_req_cb, MCAP_MDL_CB_REMOTE_RECONN_REQ, hdp_mcap_mdl_reconn_req_cb, MCAP_MDL_CB_INVALID); if (ret) return TRUE; error("Can't set mcl callbacks, closing mcl"); close_device_con(device, TRUE); return FALSE; } static void mcl_connected(struct mcap_mcl *mcl, gpointer data) { struct hdp_device *hdp_device; bdaddr_t addr; GSList *l; mcap_mcl_get_addr(mcl, &addr); l = g_slist_find_custom(devices, &addr, cmp_dev_addr); if (l == NULL) { struct hdp_adapter *hdp_adapter = data; struct btd_device *device; char str[18]; ba2str(&addr, str); device = adapter_get_device(connection, hdp_adapter->btd_adapter, str); if (!device) return; hdp_device = create_health_device(connection, device); if (!hdp_device) return; devices = g_slist_append(devices, hdp_device); } else hdp_device = l->data; hdp_device->mcl = mcap_mcl_ref(mcl); hdp_device->mcl_conn = TRUE; DBG("New mcl connected from %s", device_get_path(hdp_device->dev)); hdp_set_mcl_cb(hdp_device, NULL); } static void mcl_reconnected(struct mcap_mcl *mcl, gpointer data) { struct hdp_device *hdp_device; GSList *l; l = g_slist_find_custom(devices, mcl, cmp_dev_mcl); if (l == NULL) return; hdp_device = l->data; hdp_device->mcl_conn = TRUE; DBG("MCL reconnected %s", device_get_path(hdp_device->dev)); hdp_set_mcl_cb(hdp_device, NULL); } static void mcl_disconnected(struct mcap_mcl *mcl, gpointer data) { struct hdp_device *hdp_device; GSList *l; l = g_slist_find_custom(devices, mcl, cmp_dev_mcl); if (l == NULL) return; hdp_device = l->data; hdp_device->mcl_conn = FALSE; DBG("Mcl disconnected %s", device_get_path(hdp_device->dev)); } static void mcl_uncached(struct mcap_mcl *mcl, gpointer data) { struct hdp_device *hdp_device; const char *path; GSList *l; l = g_slist_find_custom(devices, mcl, cmp_dev_mcl); if (l == NULL) return; hdp_device = l->data; device_unref_mcl(hdp_device); if (hdp_device->sdp_present) return; /* Because remote device hasn't announced an HDP record */ /* the Bluetooth daemon won't notify when the device shall */ /* be removed. Then we have to remove the HealthDevice */ /* interface manually */ path = device_get_path(hdp_device->dev); g_dbus_unregister_interface(hdp_device->conn, path, HEALTH_DEVICE); DBG("Mcl uncached %s", path); } static void check_devices_mcl(void) { struct hdp_device *dev; GSList *l, *to_delete = NULL; for (l = devices; l; l = l->next) { dev = l->data; device_unref_mcl(dev); if (!dev->sdp_present) to_delete = g_slist_append(to_delete, dev); else remove_channels(dev); } for (l = to_delete; l; l = l->next) { const char *path; path = device_get_path(dev->dev); g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE); } g_slist_free(to_delete); } static void release_adapter_instance(struct hdp_adapter *hdp_adapter) { if (hdp_adapter->mi == NULL) return; check_devices_mcl(); mcap_release_instance(hdp_adapter->mi); mcap_instance_unref(hdp_adapter->mi); hdp_adapter->mi = NULL; } static gboolean update_adapter(struct hdp_adapter *hdp_adapter) { GError *err = NULL; bdaddr_t addr; if (applications == NULL) { release_adapter_instance(hdp_adapter); goto update; } if (hdp_adapter->mi != NULL) goto update; adapter_get_address(hdp_adapter->btd_adapter, &addr); hdp_adapter->mi = mcap_create_instance(&addr, BT_IO_SEC_MEDIUM, 0, 0, mcl_connected, mcl_reconnected, mcl_disconnected, mcl_uncached, NULL, /* CSP is not used by now */ hdp_adapter, &err); if (hdp_adapter->mi == NULL) { error("Error creating the MCAP instance: %s", err->message); g_error_free(err); return FALSE; } hdp_adapter->ccpsm = mcap_get_ctrl_psm(hdp_adapter->mi, &err); if (err != NULL) { error("Error getting MCAP control PSM: %s", err->message); goto fail; } hdp_adapter->dcpsm = mcap_get_data_psm(hdp_adapter->mi, &err); if (err != NULL) { error("Error getting MCAP data PSM: %s", err->message); goto fail; } update: if (hdp_update_sdp_record(hdp_adapter, applications)) return TRUE; error("Error updating the SDP record"); fail: release_adapter_instance(hdp_adapter); if (err != NULL) g_error_free(err); return FALSE; } int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *adapter) { struct hdp_adapter *hdp_adapter; hdp_adapter = g_new0(struct hdp_adapter, 1); hdp_adapter->btd_adapter = btd_adapter_ref(adapter); if(!update_adapter(hdp_adapter)) goto fail; adapters = g_slist_append(adapters, hdp_adapter); return 0; fail: btd_adapter_unref(hdp_adapter->btd_adapter); g_free(hdp_adapter); return -1; } void hdp_adapter_unregister(struct btd_adapter *adapter) { struct hdp_adapter *hdp_adapter; GSList *l; l = g_slist_find_custom(adapters, adapter, cmp_adapter); if (l == NULL) return; hdp_adapter = l->data; adapters = g_slist_remove(adapters, hdp_adapter); if (hdp_adapter->sdp_handler > 0) remove_record_from_server(hdp_adapter->sdp_handler); release_adapter_instance(hdp_adapter); btd_adapter_unref(hdp_adapter->btd_adapter); g_free(hdp_adapter); } static void delete_echo_channel_cb(GError *err, gpointer chan) { if (err != NULL && err->code != MCAP_INVALID_MDL) { /* TODO: Decide if more action is required here */ error("Error deleting echo channel: %s", err->message); return; } health_channel_destroy(chan); } static void delete_echo_channel(struct hdp_channel *chan) { GError *err = NULL; if (!chan->dev->mcl_conn) { error("Echo channel cannot be deleted: mcl closed"); return; } if (mcap_delete_mdl(chan->mdl, delete_echo_channel_cb, hdp_channel_ref(chan), (GDestroyNotify) hdp_channel_unref, &err)) return; hdp_channel_unref(chan); error("Error deleting the echo channel: %s", err->message); g_error_free(err); /* TODO: Decide if more action is required here */ } static void abort_echo_channel_cb(GError *err, gpointer data) { struct hdp_channel *chan = data; if (err != NULL && err->code != MCAP_ERROR_INVALID_OPERATION) { error("Aborting error: %s", err->message); if (err->code == MCAP_INVALID_MDL) { /* MDL is removed from MCAP so we can */ /* free the data channel without sending */ /* a MD_DELETE_MDL_REQ */ /* TODO review the above comment */ /* hdp_channel_unref(chan); */ } return; } delete_echo_channel(chan); } static void destroy_create_dc_data(gpointer data) { struct hdp_create_dc *dc_data = data; hdp_create_data_unref(dc_data); } static void *generate_echo_packet(void) { uint8_t *buf; int i; buf = g_malloc(HDP_ECHO_LEN); srand(time(NULL)); for(i = 0; i < HDP_ECHO_LEN; i++) buf[i] = rand() % UINT8_MAX; return buf; } static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond, gpointer data) { struct hdp_tmp_dc_data *hdp_conn = data; struct hdp_echo_data *edata = hdp_conn->hdp_chann->edata; struct hdp_channel *chan = hdp_conn->hdp_chann; uint8_t buf[MCAP_DC_MTU]; DBusMessage *reply; gboolean value; int fd, len; if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { value = FALSE; goto end; } fd = g_io_channel_unix_get_fd(io_chan); len = read(fd, buf, sizeof(buf)); if (len != HDP_ECHO_LEN) { value = FALSE; goto end; } value = (memcmp(buf, edata->buf, len) == 0); end: reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value, DBUS_TYPE_INVALID); g_dbus_send_message(hdp_conn->conn, reply); g_source_remove(edata->tid); edata->tid = 0; g_free(edata->buf); edata->buf = NULL; if (!value) close_device_con(chan->dev, FALSE); else delete_echo_channel(chan); hdp_tmp_dc_data_unref(hdp_conn); return FALSE; } static gboolean echo_timeout(gpointer data) { struct hdp_channel *chan = data; GIOChannel *io; int fd; error("Error: Echo request timeout"); chan->edata->tid = 0; fd = mcap_mdl_get_fd(chan->mdl); if (fd < 0) return FALSE; io = g_io_channel_unix_new(fd); g_io_channel_shutdown(io, TRUE, NULL); return FALSE; } static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err, gpointer data) { struct hdp_tmp_dc_data *hdp_conn = data; struct hdp_echo_data *edata; GError *gerr = NULL; DBusMessage *reply; GIOChannel *io; int fd; if (err != NULL) { reply = g_dbus_create_error(hdp_conn->msg, ERROR_INTERFACE ".HealthError", "%s", err->message); g_dbus_send_message(hdp_conn->conn, reply); /* Send abort request because remote */ /* side is now in PENDING state. */ if (!mcap_mdl_abort(hdp_conn->hdp_chann->mdl, abort_echo_channel_cb, hdp_channel_ref(hdp_conn->hdp_chann), (GDestroyNotify) hdp_channel_unref, &gerr)) { error("%s", gerr->message); g_error_free(gerr); hdp_channel_unref(hdp_conn->hdp_chann); } return; } fd = mcap_mdl_get_fd(hdp_conn->hdp_chann->mdl); if (fd < 0) { reply = g_dbus_create_error(hdp_conn->msg, ERROR_INTERFACE ".HealthError", "Can't write in echo channel"); g_dbus_send_message(hdp_conn->conn, reply); delete_echo_channel(hdp_conn->hdp_chann); return; } edata = hdp_conn->hdp_chann->edata; edata->buf = generate_echo_packet(); send_echo_data(fd, edata->buf, HDP_ECHO_LEN); io = g_io_channel_unix_new(fd); g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_IN, check_echo, hdp_tmp_dc_data_ref(hdp_conn)); edata->tid = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, ECHO_TIMEOUT, echo_timeout, hdp_channel_ref(hdp_conn->hdp_chann), (GDestroyNotify) hdp_channel_unref); g_io_channel_unref(io); } static void delete_mdl_cb(GError *err, gpointer data) { if (err != NULL) error("Deleting error: %s", err->message); } static void abort_and_del_mdl_cb(GError *err, gpointer data) { struct mcap_mdl *mdl = data; GError *gerr = NULL; if (err != NULL) { error("%s", err->message); if (err->code == MCAP_INVALID_MDL) { /* MDL is removed from MCAP so we don't */ /* need to delete it. */ return; } } if (!mcap_delete_mdl(mdl, delete_mdl_cb, NULL, NULL, &gerr)) { error("%s", gerr->message); g_error_free(gerr); } } static void abort_mdl_connection_cb(GError *err, gpointer data) { struct hdp_tmp_dc_data *hdp_conn = data; struct hdp_channel *hdp_chann = hdp_conn->hdp_chann; if (err != NULL) error("Aborting error: %s", err->message); /* Connection operation has failed but we have to */ /* notify the channel created at MCAP level */ if (hdp_chann->mdep != HDP_MDEP_ECHO) g_dbus_emit_signal(hdp_conn->conn, device_get_path(hdp_chann->dev->dev), HEALTH_DEVICE, "ChannelConnected", DBUS_TYPE_OBJECT_PATH, &hdp_chann->path, DBUS_TYPE_INVALID); } static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data) { struct hdp_tmp_dc_data *hdp_conn = data; struct hdp_channel *hdp_chann = hdp_conn->hdp_chann; struct hdp_device *dev = hdp_chann->dev; DBusMessage *reply; GError *gerr = NULL; if (err != NULL) { error("%s", err->message); reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_OBJECT_PATH, &hdp_chann->path, DBUS_TYPE_INVALID); g_dbus_send_message(hdp_conn->conn, reply); /* Send abort request because remote side */ /* is now in PENDING state */ if (!mcap_mdl_abort(hdp_chann->mdl, abort_mdl_connection_cb, hdp_tmp_dc_data_ref(hdp_conn), hdp_tmp_dc_data_destroy, &gerr)) { hdp_tmp_dc_data_unref(hdp_conn); error("%s", gerr->message); g_error_free(gerr); } return; } reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_OBJECT_PATH, &hdp_chann->path, DBUS_TYPE_INVALID); g_dbus_send_message(hdp_conn->conn, reply); g_dbus_emit_signal(hdp_conn->conn, device_get_path(hdp_chann->dev->dev), HEALTH_DEVICE, "ChannelConnected", DBUS_TYPE_OBJECT_PATH, &hdp_chann->path, DBUS_TYPE_INVALID); if (!check_channel_conf(hdp_chann)) { close_mdl(hdp_chann); return; } if (dev->fr != NULL) return; dev->fr = hdp_channel_ref(hdp_chann); emit_property_changed(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE, "MainChannel", DBUS_TYPE_OBJECT_PATH, &dev->fr->path); } static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf, GError *err, gpointer data) { struct hdp_create_dc *user_data = data; struct hdp_tmp_dc_data *hdp_conn; struct hdp_channel *hdp_chan; GError *gerr = NULL; DBusMessage *reply; if (err != NULL) { reply = g_dbus_create_error(user_data->msg, ERROR_INTERFACE ".HealthError", "%s", err->message); g_dbus_send_message(user_data->conn, reply); return; } if (user_data->mdep != HDP_MDEP_ECHO && user_data->config == HDP_NO_PREFERENCE_DC) { if (user_data->dev->fr == NULL && conf != HDP_RELIABLE_DC) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Data channel aborted, first data " "channel should be reliable"); goto fail; } else if (conf == HDP_NO_PREFERENCE_DC || conf > HDP_STREAMING_DC) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Data channel aborted, " "configuration error"); goto fail; } } hdp_chan = create_channel(user_data->dev, conf, mdl, mcap_mdl_get_mdlid(mdl), user_data->app, &gerr); if (hdp_chan == NULL) goto fail; hdp_conn = g_new0(struct hdp_tmp_dc_data, 1); hdp_conn->msg = dbus_message_ref(user_data->msg); hdp_conn->conn = dbus_connection_ref(user_data->conn); hdp_conn->hdp_chann = hdp_chan; hdp_conn->cb = user_data->cb; hdp_chan->mdep = user_data->mdep; if (hdp_get_dcpsm(hdp_chan->dev, hdp_get_dcpsm_cb, hdp_tmp_dc_data_ref(hdp_conn), hdp_tmp_dc_data_destroy, &gerr)) return; error("%s", gerr->message); g_error_free(gerr); reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_OBJECT_PATH, &hdp_chan->path, DBUS_TYPE_INVALID); g_dbus_send_message(hdp_conn->conn, reply); hdp_tmp_dc_data_unref(hdp_conn); /* Send abort request because remote side is now in PENDING state */ if (!mcap_mdl_abort(hdp_chan->mdl, abort_mdl_connection_cb, hdp_tmp_dc_data_ref(hdp_conn), hdp_tmp_dc_data_destroy, &gerr)) { hdp_tmp_dc_data_unref(hdp_conn); error("%s", gerr->message); g_error_free(gerr); } return; fail: reply = g_dbus_create_error(user_data->msg, ERROR_INTERFACE ".HealthError", "%s", gerr->message); g_dbus_send_message(user_data->conn, reply); g_error_free(gerr); /* Send abort request because remote side is now in PENDING */ /* state. Then we have to delete it because we couldn't */ /* register the HealthChannel interface */ if (!mcap_mdl_abort(mdl, abort_and_del_mdl_cb, mcap_mdl_ref(mdl), (GDestroyNotify) mcap_mdl_unref, &gerr)) { error("%s", gerr->message); g_error_free(gerr); mcap_mdl_unref(mdl); } } static void device_create_dc_cb(gpointer user_data, GError *err) { struct hdp_create_dc *data = user_data; DBusMessage *reply; GError *gerr = NULL; if (err != NULL) { reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError", "%s", err->message); g_dbus_send_message(data->conn, reply); return; } if (data->dev->mcl == NULL) { g_set_error(&gerr, HDP_ERROR, HDP_CONNECTION_ERROR, "Mcl was closed"); goto fail; } hdp_create_data_ref(data); if (mcap_create_mdl(data->dev->mcl, data->mdep, data->config, device_create_mdl_cb, data, destroy_create_dc_data, &gerr)) return; hdp_create_data_unref(data); fail: reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError", "%s", gerr->message); g_error_free(gerr); g_dbus_send_message(data->conn, reply); } static DBusMessage *device_echo(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct hdp_device *device = user_data; struct hdp_create_dc *data; DBusMessage *reply; GError *err = NULL; data = g_new0(struct hdp_create_dc, 1); data->dev = health_device_ref(device); data->mdep = HDP_MDEP_ECHO; data->config = HDP_RELIABLE_DC; data->msg = dbus_message_ref(msg); data->conn = dbus_connection_ref(conn); data->cb = hdp_echo_connect_cb; hdp_create_data_ref(data); if (device->mcl_conn && device->mcl != NULL) { if (mcap_create_mdl(device->mcl, data->mdep, data->config, device_create_mdl_cb, data, destroy_create_dc_data, &err)) return NULL; goto fail; } if (hdp_establish_mcl(data->dev, device_create_dc_cb, data, destroy_create_dc_data, &err)) return NULL; fail: reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError", "%s", err->message); g_error_free(err); hdp_create_data_unref(data); return reply; } static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err) { struct hdp_create_dc *dc_data, *user_data = data; DBusMessage *reply; GError *gerr = NULL; if (err != NULL) { reply = g_dbus_create_error(user_data->msg, ERROR_INTERFACE ".HealthError", "%s", err->message); g_dbus_send_message(user_data->conn, reply); return; } dc_data = hdp_create_data_ref(user_data); dc_data->mdep = mdep; if (user_data->dev->mcl_conn) { device_create_dc_cb(dc_data, NULL); hdp_create_data_unref(dc_data); return; } if (hdp_establish_mcl(dc_data->dev, device_create_dc_cb, dc_data, destroy_create_dc_data, &gerr)) return; reply = g_dbus_create_error(user_data->msg, ERROR_INTERFACE ".HealthError", "%s", gerr->message); hdp_create_data_unref(dc_data); g_error_free(gerr); g_dbus_send_message(user_data->conn, reply); } static DBusMessage *device_create_channel(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct hdp_device *device = user_data; struct hdp_application *app; struct hdp_create_dc *data; char *app_path, *conf; DBusMessage *reply; GError *err = NULL; uint8_t config; GSList *l; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &app_path, DBUS_TYPE_STRING, &conf, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); l = g_slist_find_custom(applications, app_path, cmp_app); if (l == NULL) return btd_error_invalid_args(msg); app = l->data; if (g_ascii_strcasecmp("Reliable", conf) == 0) config = HDP_RELIABLE_DC; else if (g_ascii_strcasecmp("Streaming", conf) == 0) config = HDP_STREAMING_DC; else if (g_ascii_strcasecmp("Any", conf) == 0) config = HDP_NO_PREFERENCE_DC; else return btd_error_invalid_args(msg); if (app->role == HDP_SINK && config != HDP_NO_PREFERENCE_DC) return btd_error_invalid_args(msg); if (app->role == HDP_SOURCE && config == HDP_NO_PREFERENCE_DC) return btd_error_invalid_args(msg); if (!device->fr && config == HDP_STREAMING_DC) return btd_error_invalid_args(msg); data = g_new0(struct hdp_create_dc, 1); data->dev = health_device_ref(device); data->config = config; data->app = hdp_application_ref(app); data->msg = dbus_message_ref(msg); data->conn = dbus_connection_ref(conn); data->cb = hdp_mdl_conn_cb; if (hdp_get_mdep(device, l->data, device_get_mdep_cb, hdp_create_data_ref(data), destroy_create_dc_data, &err)) return NULL; reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError", "%s", err->message); g_error_free(err); hdp_create_data_unref(data); return reply; } static void hdp_mdl_delete_cb(GError *err, gpointer data) { struct hdp_tmp_dc_data *del_data = data; DBusMessage *reply; char *path; if (err != NULL && err->code != MCAP_INVALID_MDL) { reply = g_dbus_create_error(del_data->msg, ERROR_INTERFACE ".HealthError", "%s", err->message); g_dbus_send_message(del_data->conn, reply); return; } path = g_strdup(del_data->hdp_chann->path); g_dbus_unregister_interface(del_data->conn, path, HEALTH_CHANNEL); g_free(path); reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID); g_dbus_send_message(del_data->conn, reply); } static void hdp_continue_del_cb(gpointer user_data, GError *err) { struct hdp_tmp_dc_data *del_data = user_data; GError *gerr = NULL; DBusMessage *reply; if (err != NULL) { reply = g_dbus_create_error(del_data->msg, ERROR_INTERFACE ".HealthError", "%s", err->message); g_dbus_send_message(del_data->conn, reply); return; } if (mcap_delete_mdl(del_data->hdp_chann->mdl, hdp_mdl_delete_cb, hdp_tmp_dc_data_ref(del_data), hdp_tmp_dc_data_destroy, &gerr)) return; reply = g_dbus_create_error(del_data->msg, ERROR_INTERFACE ".HealthError", "%s", gerr->message); hdp_tmp_dc_data_unref(del_data); g_error_free(gerr); g_dbus_send_message(del_data->conn, reply); } static DBusMessage *device_destroy_channel(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct hdp_device *device = user_data; struct hdp_tmp_dc_data *del_data; struct hdp_channel *hdp_chan; DBusMessage *reply; GError *err = NULL; char *path; GSList *l; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)){ return btd_error_invalid_args(msg); } l = g_slist_find_custom(device->channels, path, cmp_chan_path); if (l == NULL) return btd_error_invalid_args(msg); hdp_chan = l->data; del_data = g_new0(struct hdp_tmp_dc_data, 1); del_data->msg = dbus_message_ref(msg); del_data->conn = dbus_connection_ref(conn); del_data->hdp_chann = hdp_channel_ref(hdp_chan); if (device->mcl_conn) { if (mcap_delete_mdl(hdp_chan->mdl, hdp_mdl_delete_cb, hdp_tmp_dc_data_ref(del_data), hdp_tmp_dc_data_destroy, &err)) return NULL; goto fail; } if (hdp_establish_mcl(device, hdp_continue_del_cb, hdp_tmp_dc_data_ref(del_data), hdp_tmp_dc_data_destroy, &err)) return NULL; fail: reply = g_dbus_create_error(msg, ERROR_INTERFACE ".HealthError", "%s", err->message); hdp_tmp_dc_data_unref(del_data); g_error_free(err); return reply; } static DBusMessage *device_get_properties(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct hdp_device *device = user_data; DBusMessageIter iter, dict; DBusMessage *reply; reply = dbus_message_new_method_return(msg); if (reply == NULL) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); if (device->fr != NULL) dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH, &device->fr->path); dbus_message_iter_close_container(&iter, &dict); return reply; } static void health_device_destroy(void *data) { struct hdp_device *device = data; DBG("Unregistered interface %s on path %s", HEALTH_DEVICE, device_get_path(device->dev)); remove_channels(device); if (device->ndc != NULL) { hdp_channel_unref(device->ndc); device->ndc = NULL; } devices = g_slist_remove(devices, device); health_device_unref(device); } static const GDBusMethodTable health_device_methods[] = { { GDBUS_ASYNC_METHOD("Echo", NULL, GDBUS_ARGS({ "value", "b" }), device_echo) }, { GDBUS_ASYNC_METHOD("CreateChannel", GDBUS_ARGS({ "application", "o" }, { "configuration", "s" }), GDBUS_ARGS({ "channel", "o" }), device_create_channel) }, { GDBUS_ASYNC_METHOD("DestroyChannel", GDBUS_ARGS({ "channel", "o" }), NULL, device_destroy_channel) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), device_get_properties) }, { } }; static const GDBusSignalTable health_device_signals[] = { { GDBUS_SIGNAL("ChannelConnected", GDBUS_ARGS({ "channel", "o" })) }, { GDBUS_SIGNAL("ChannelDeleted", GDBUS_ARGS({ "channel", "o" })) }, { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static struct hdp_device *create_health_device(DBusConnection *conn, struct btd_device *device) { struct btd_adapter *adapter = device_get_adapter(device); const gchar *path = device_get_path(device); struct hdp_device *dev; GSList *l; if (device == NULL) return NULL; dev = g_new0(struct hdp_device, 1); dev->conn = dbus_connection_ref(conn); dev->dev = btd_device_ref(device); health_device_ref(dev); l = g_slist_find_custom(adapters, adapter, cmp_adapter); if (l == NULL) goto fail; dev->hdp_adapter = l->data; if (!g_dbus_register_interface(conn, path, HEALTH_DEVICE, health_device_methods, health_device_signals, NULL, dev, health_device_destroy)) { error("D-Bus failed to register %s interface", HEALTH_DEVICE); goto fail; } DBG("Registered interface %s on path %s", HEALTH_DEVICE, path); return dev; fail: health_device_unref(dev); return NULL; } int hdp_device_register(DBusConnection *conn, struct btd_device *device) { struct hdp_device *hdev; GSList *l; l = g_slist_find_custom(devices, device, cmp_device); if (l != NULL) { hdev = l->data; hdev->sdp_present = TRUE; return 0; } hdev = create_health_device(conn, device); if (hdev == NULL) return -1; hdev->sdp_present = TRUE; devices = g_slist_prepend(devices, hdev); return 0; } void hdp_device_unregister(struct btd_device *device) { struct hdp_device *hdp_dev; const char *path; GSList *l; l = g_slist_find_custom(devices, device, cmp_device); if (l == NULL) return; hdp_dev = l->data; path = device_get_path(hdp_dev->dev); g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE); } int hdp_manager_start(DBusConnection *conn) { DBG("Starting Health manager"); if (!g_dbus_register_interface(conn, MANAGER_PATH, HEALTH_MANAGER, health_manager_methods, NULL, NULL, NULL, manager_path_unregister)) { error("D-Bus failed to register %s interface", HEALTH_MANAGER); return -1; } connection = dbus_connection_ref(conn); return 0; } void hdp_manager_stop(void) { g_dbus_unregister_interface(connection, MANAGER_PATH, HEALTH_MANAGER); dbus_connection_unref(connection); DBG("Stopped Health manager"); } struct hdp_device *health_device_ref(struct hdp_device *hdp_dev) { hdp_dev->ref++; DBG("health_device_ref(%p): ref=%d", hdp_dev, hdp_dev->ref); return hdp_dev; } void health_device_unref(struct hdp_device *hdp_dev) { hdp_dev->ref--; DBG("health_device_unref(%p): ref=%d", hdp_dev, hdp_dev->ref); if (hdp_dev->ref > 0) return; free_health_device(hdp_dev); } bluez-4.101/health/hdp_util.h0000644000000000000000000000405311766125764012776 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __HDP_UTIL_H__ #define __HDP_UTIL_H__ typedef void (*hdp_continue_mdep_f)(uint8_t mdep, gpointer user_data, GError *err); typedef void (*hdp_continue_dcpsm_f)(uint16_t dcpsm, gpointer user_data, GError *err); typedef void (*hdp_continue_proc_f)(gpointer user_data, GError *err); struct hdp_application *hdp_get_app_config(DBusMessageIter *iter, GError **err); gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list); gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app, hdp_continue_mdep_f func, gpointer data, GDestroyNotify destroy, GError **err); gboolean hdp_establish_mcl(struct hdp_device *device, hdp_continue_proc_f func, gpointer data, GDestroyNotify destroy, GError **err); gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func, gpointer data, GDestroyNotify destroy, GError **err); struct hdp_application *hdp_application_ref(struct hdp_application *app); void hdp_application_unref(struct hdp_application *app); struct hdp_device *health_device_ref(struct hdp_device *hdp_dev); void health_device_unref(struct hdp_device *hdp_dev); #endif /* __HDP_UTIL_H__ */ bluez-4.101/health/hdp_types.h0000644000000000000000000001000411766125764013156 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 GSyC/LibreSoft, Universidad Rey Juan Carlos. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __HDP_TYPES_H__ #define __HDP_TYPES_H__ #define MANAGER_PATH "/org/bluez" #define HEALTH_MANAGER "org.bluez.HealthManager" #define HEALTH_DEVICE "org.bluez.HealthDevice" #define HEALTH_CHANNEL "org.bluez.HealthChannel" #define HDP_VERSION 0x0100 #define HDP_SERVICE_NAME "Bluez HDP" #define HDP_SERVICE_DSC "A Bluez health device profile implementation" #define HDP_SERVICE_PROVIDER "Bluez" #define HDP_MDEP_ECHO 0x00 #define HDP_MDEP_INITIAL 0x01 #define HDP_MDEP_FINAL 0x7F #define HDP_ERROR g_quark_from_static_string("hdp-error-quark") #define HDP_NO_PREFERENCE_DC 0x00 #define HDP_RELIABLE_DC 0x01 #define HDP_STREAMING_DC 0x02 #define HDP_SINK_ROLE_AS_STRING "sink" #define HDP_SOURCE_ROLE_AS_STRING "source" typedef enum { HDP_SOURCE = 0x00, HDP_SINK = 0x01 } HdpRole; typedef enum { HDP_DIC_PARSE_ERROR, HDP_DIC_ENTRY_PARSE_ERROR, HDP_CONNECTION_ERROR, HDP_UNSPECIFIED_ERROR, HDP_UNKNOWN_ERROR } HdpError; enum data_specs { DATA_EXCHANGE_SPEC_11073 = 0x01 }; struct hdp_application { DBusConnection *conn; /* For dbus watcher */ char *path; /* The path of the application */ uint16_t data_type; /* Data type handled for this application */ gboolean data_type_set; /* Flag for dictionary parsing */ uint8_t role; /* Role of this application */ gboolean role_set; /* Flag for dictionary parsing */ uint8_t chan_type; /* QoS preferred by source applications */ gboolean chan_type_set; /* Flag for dictionary parsing */ char *description; /* Options description for SDP record */ uint8_t id; /* The identification is also the mdepid */ char *oname; /* Name of the owner application */ guint dbus_watcher; /* Watch for clients disconnection */ gint ref; /* Reference counter */ }; struct hdp_adapter { struct btd_adapter *btd_adapter; /* Bluetooth adapter */ struct mcap_instance *mi; /* Mcap instance in */ uint16_t ccpsm; /* Control channel psm */ uint16_t dcpsm; /* Data channel psm */ uint32_t sdp_handler; /* SDP record handler */ uint32_t record_state; /* Service record state */ }; struct hdp_device { DBusConnection *conn; /* For name listener handling */ struct btd_device *dev; /* Device reference */ struct hdp_adapter *hdp_adapter; /* hdp_adapater */ struct mcap_mcl *mcl; /* The mcap control channel */ gboolean mcl_conn; /* Mcl status */ gboolean sdp_present; /* Has an sdp record */ GSList *channels; /* Data Channel list */ struct hdp_channel *ndc; /* Data channel being negotiated */ struct hdp_channel *fr; /* First reliable data channel */ gint ref; /* Reference counting */ }; struct hdp_echo_data; struct hdp_channel { struct hdp_device *dev; /* Device where this channel belongs */ struct hdp_application *app; /* Application */ struct mcap_mdl *mdl; /* The data channel reference */ char *path; /* The path of the channel */ uint8_t config; /* Channel configuration */ uint8_t mdep; /* Remote MDEP */ uint16_t mdlid; /* Data channel Id */ uint16_t imtu; /* Channel incoming MTU */ uint16_t omtu; /* Channel outgoing MTU */ struct hdp_echo_data *edata; /* private data used by echo channels */ gint ref; /* Reference counter */ }; #endif /* __HDP_TYPES_H__ */ bluez-4.101/scripts/0000755000000000000000000000000011771120005011270 500000000000000bluez-4.101/scripts/bluetooth-hid2hci.rules0000644000000000000000000000251411766125764015630 00000000000000# do not edit this file, it will be overwritten on update ACTION=="remove", GOTO="hid2hci_end" SUBSYSTEM!="usb", GOTO="hid2hci_end" # Variety of Dell Bluetooth devices - match on a mouse device that is # self powered and where a HID report needs to be sent to switch modes # Known supported devices: 413c:8154, 413c:8158, 413c:8162 ATTR{bInterfaceClass}=="03", ATTR{bInterfaceSubClass}=="01", ATTR{bInterfaceProtocol}=="02", \ ATTRS{bDeviceClass}=="00", ATTRS{idVendor}=="413c", ATTRS{bmAttributes}=="e0", \ RUN+="hid2hci --method=dell --devpath=%p", ENV{HID2HCI_SWITCH}="1" # Logitech devices KERNEL=="hiddev*", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c70[345abce]|c71[34bc]", \ RUN+="hid2hci --method=logitech-hid --devpath=%p" ENV{DEVTYPE}!="usb_device", GOTO="hid2hci_end" # When a Dell device recovers from S3, the mouse child needs to be repoked # Unfortunately the only event seen is the BT device disappearing, so the mouse # device needs to be chased down on the USB bus. ATTR{bDeviceClass}=="e0", ATTR{bDeviceSubClass}=="01", ATTR{bDeviceProtocol}=="01", ATTR{idVendor}=="413c", \ ENV{REMOVE_CMD}="/sbin/udevadm trigger --action=change --subsystem-match=usb --property-match=HID2HCI_SWITCH=1" # CSR devices ATTR{idVendor}=="0a12|0458|05ac", ATTR{idProduct}=="1000", RUN+="hid2hci --method=csr --devpath=%p" LABEL="hid2hci_end" bluez-4.101/scripts/bluetooth-serial.rules0000644000000000000000000000435311272762165015572 00000000000000# Brain Boxes BL-620 Bluetooth Adapter SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="Brain Boxes", ATTRS{prod_id2}=="Bluetooth PC Card", ENV{HCIOPTS}="bboxes", RUN+="bluetooth_serial" # Xircom CreditCard Bluetooth Adapter SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="Xircom", ATTRS{prod_id3}=="CBT", ENV{HCIOPTS}="xircom", RUN+="bluetooth_serial" # Xircom RealPort2 Bluetooth Adapter SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="Xircom", ATTRS{prod_id3}=="CBT", ENV{HCIOPTS}="xircom", RUN+="bluetooth_serial" # IBM Bluetooth PC Card II SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="IBM", ATTRS{prod_id2}=="Bluetooth PC Card II", ENV{HCIOPTS}="tdk", RUN+="bluetooth_serial" # TDK Bluetooth PC Card SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="TDK", ATTRS{prod_id2}=="Bluetooth PC Card II", ENV{HCIOPTS}="tdk", RUN+="bluetooth_serial" # AmbiCom BT2000C Bluetooth PC/CF Card SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="AmbiCom BT2000C", ATTRS{prod_id2}=="Bluetooth PC/CF Card", ENV{HCIOPTS}="bt2000c", RUN+="bluetooth_serial" # COM One Platinium Bluetooth PC Card SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="COM1 SA", ATTRS{prod_id2}=="MC310 CARD", ENV{HCIOPTS}="comone", RUN+="bluetooth_serial" # Sphinx PICO Card SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="SPHINX", ATTRS{prod_id2}=="BT-CARD", ENV{HCIOPTS}="picocard", RUN+="bluetooth_serial" # H-Soft blue+Card SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="H-Soft", ATTRS{prod_id2}=="Blue+CARD", ENV{HCIOPTS}="$sysfs{manf_id},$sysfs{card_id}", RUN+="bluetooth_serial" # Compaq iPAQ Bluetooth Sleeve, Belkin F8T020, any other muppet who used an OXCF950 and didn't bother to program it appropriately. SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="CF CARD", ATTRS{prod_id2}=="GENERIC", ENV{HCIOPTS}="$sysfs{manf_id},$sysfs{card_id}", RUN+="bluetooth_serial" # Zoom Bluetooth Card and Sitecom CN-504 Card SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="PCMCIA", ATTRS{prod_id2}=="Bluetooth Card", ENV{HCIOPTS}="zoom", RUN+="bluetooth_serial" # CC&C BT0100M SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="Bluetooth BT0100M", ENV{HCIOPTS}="bcsp 115200", RUN+="bluetooth_serial" bluez-4.101/scripts/bluetooth_serial0000644000000000000000000000116711071665350014516 00000000000000#!/bin/sh # # bluetooth_serial # # Bluetooth serial PCMCIA card initialization # start_serial() { if [ ! -x /bin/setserial -o ! -x /usr/sbin/hciattach ]; then logger "$0: setserial or hciattach not executable, cannot start $DEVNAME" return 1 fi if [ "$BAUDBASE" != "" ]; then /bin/setserial $DEVNAME baud_base $BAUDBASE fi /usr/sbin/hciattach $DEVNAME $HCIOPTS 2>&1 | logger -t hciattach } stop_serial() { [ -x /bin/fuser ] || return 1 /bin/fuser -k -HUP $DEVNAME > /dev/null } case "$ACTION" in add) start_serial ;; remove) stop_serial ;; *) logger "Unknown action received $0: $ACTION" ;; esac bluez-4.101/attrib/0000755000000000000000000000000011771120004011065 500000000000000bluez-4.101/attrib/gatt.h0000644000000000000000000000633311766125764012150 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include /* GATT Profile Attribute types */ #define GATT_PRIM_SVC_UUID 0x2800 #define GATT_SND_SVC_UUID 0x2801 #define GATT_INCLUDE_UUID 0x2802 #define GATT_CHARAC_UUID 0x2803 /* GATT Characteristic Types */ #define GATT_CHARAC_DEVICE_NAME 0x2A00 #define GATT_CHARAC_APPEARANCE 0x2A01 #define GATT_CHARAC_PERIPHERAL_PRIV_FLAG 0x2A02 #define GATT_CHARAC_RECONNECTION_ADDRESS 0x2A03 #define GATT_CHARAC_PERIPHERAL_PREF_CONN 0x2A04 #define GATT_CHARAC_SERVICE_CHANGED 0x2A05 /* GATT Characteristic Descriptors */ #define GATT_CHARAC_EXT_PROPER_UUID 0x2900 #define GATT_CHARAC_USER_DESC_UUID 0x2901 #define GATT_CLIENT_CHARAC_CFG_UUID 0x2902 #define GATT_SERVER_CHARAC_CFG_UUID 0x2903 #define GATT_CHARAC_FMT_UUID 0x2904 #define GATT_CHARAC_AGREG_FMT_UUID 0x2905 #define GATT_CHARAC_VALID_RANGE_UUID 0x2906 /* Client Characteristic Configuration bit field */ #define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001 #define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002 typedef void (*gatt_cb_t) (GSList *l, guint8 status, gpointer user_data); struct gatt_primary { char uuid[MAX_LEN_UUID_STR + 1]; struct att_range range; }; struct gatt_char { char uuid[MAX_LEN_UUID_STR + 1]; uint16_t handle; uint8_t properties; uint16_t value_handle; }; guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func, gpointer user_data); guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end, bt_uuid_t *uuid, gatt_cb_t func, gpointer user_data); guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset, GAttribResultFunc func, gpointer user_data); guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen, GAttribResultFunc func, gpointer user_data); guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end, GAttribResultFunc func, gpointer user_data); guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen, GDestroyNotify notify, gpointer user_data); guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end, bt_uuid_t *uuid, GAttribResultFunc func, gpointer user_data); guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func, gpointer user_data); gboolean gatt_parse_record(const sdp_record_t *rec, uuid_t *prim_uuid, uint16_t *psm, uint16_t *start, uint16_t *end); bluez-4.101/attrib/gatttool.c0000644000000000000000000003600111766125764013034 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "att.h" #include "btio.h" #include "gattrib.h" #include "gatt.h" #include "gatttool.h" static gchar *opt_src = NULL; static gchar *opt_dst = NULL; static gchar *opt_dst_type = NULL; static gchar *opt_value = NULL; static gchar *opt_sec_level = NULL; static bt_uuid_t *opt_uuid = NULL; static int opt_start = 0x0001; static int opt_end = 0xffff; static int opt_handle = -1; static int opt_mtu = 0; static int opt_psm = 0; static int opt_offset = 0; static gboolean opt_primary = FALSE; static gboolean opt_characteristics = FALSE; static gboolean opt_char_read = FALSE; static gboolean opt_listen = FALSE; static gboolean opt_char_desc = FALSE; static gboolean opt_char_write = FALSE; static gboolean opt_char_write_req = FALSE; static gboolean opt_interactive = FALSE; static GMainLoop *event_loop; static gboolean got_error = FALSE; static GSourceFunc operation; struct characteristic_data { GAttrib *attrib; uint16_t start; uint16_t end; }; static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data) { GAttrib *attrib = user_data; uint8_t opdu[ATT_MAX_MTU]; uint16_t handle, i, olen = 0; handle = att_get_u16(&pdu[1]); switch (pdu[0]) { case ATT_OP_HANDLE_NOTIFY: g_print("Notification handle = 0x%04x value: ", handle); break; case ATT_OP_HANDLE_IND: g_print("Indication handle = 0x%04x value: ", handle); break; default: g_print("Invalid opcode\n"); return; } for (i = 3; i < len; i++) g_print("%02x ", pdu[i]); g_print("\n"); if (pdu[0] == ATT_OP_HANDLE_NOTIFY) return; olen = enc_confirmation(opdu, sizeof(opdu)); if (olen > 0) g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL); } static gboolean listen_start(gpointer user_data) { GAttrib *attrib = user_data; g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, events_handler, attrib, NULL); g_attrib_register(attrib, ATT_OP_HANDLE_IND, events_handler, attrib, NULL); return FALSE; } static void connect_cb(GIOChannel *io, GError *err, gpointer user_data) { GAttrib *attrib; if (err) { g_printerr("%s\n", err->message); got_error = TRUE; g_main_loop_quit(event_loop); } attrib = g_attrib_new(io); if (opt_listen) g_idle_add(listen_start, attrib); operation(attrib); } static void primary_all_cb(GSList *services, guint8 status, gpointer user_data) { GSList *l; if (status) { g_printerr("Discover all primary services failed: %s\n", att_ecode2str(status)); goto done; } for (l = services; l; l = l->next) { struct gatt_primary *prim = l->data; g_print("attr handle = 0x%04x, end grp handle = 0x%04x " "uuid: %s\n", prim->range.start, prim->range.end, prim->uuid); } done: g_main_loop_quit(event_loop); } static void primary_by_uuid_cb(GSList *ranges, guint8 status, gpointer user_data) { GSList *l; if (status != 0) { g_printerr("Discover primary services by UUID failed: %s\n", att_ecode2str(status)); goto done; } for (l = ranges; l; l = l->next) { struct att_range *range = l->data; g_print("Starting handle: %04x Ending handle: %04x\n", range->start, range->end); } done: g_main_loop_quit(event_loop); } static gboolean primary(gpointer user_data) { GAttrib *attrib = user_data; if (opt_uuid) gatt_discover_primary(attrib, opt_uuid, primary_by_uuid_cb, NULL); else gatt_discover_primary(attrib, NULL, primary_all_cb, NULL); return FALSE; } static void char_discovered_cb(GSList *characteristics, guint8 status, gpointer user_data) { GSList *l; if (status) { g_printerr("Discover all characteristics failed: %s\n", att_ecode2str(status)); goto done; } for (l = characteristics; l; l = l->next) { struct gatt_char *chars = l->data; g_print("handle = 0x%04x, char properties = 0x%02x, char value " "handle = 0x%04x, uuid = %s\n", chars->handle, chars->properties, chars->value_handle, chars->uuid); } done: g_main_loop_quit(event_loop); } static gboolean characteristics(gpointer user_data) { GAttrib *attrib = user_data; gatt_discover_char(attrib, opt_start, opt_end, opt_uuid, char_discovered_cb, NULL); return FALSE; } static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { uint8_t value[ATT_MAX_MTU]; int i, vlen; if (status != 0) { g_printerr("Characteristic value/descriptor read failed: %s\n", att_ecode2str(status)); goto done; } if (!dec_read_resp(pdu, plen, value, &vlen)) { g_printerr("Protocol error\n"); goto done; } g_print("Characteristic value/descriptor: "); for (i = 0; i < vlen; i++) g_print("%02x ", value[i]); g_print("\n"); done: if (opt_listen == FALSE) g_main_loop_quit(event_loop); } static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct characteristic_data *char_data = user_data; struct att_data_list *list; int i; if (status == ATT_ECODE_ATTR_NOT_FOUND && char_data->start != opt_start) goto done; if (status != 0) { g_printerr("Read characteristics by UUID failed: %s\n", att_ecode2str(status)); goto done; } list = dec_read_by_type_resp(pdu, plen); if (list == NULL) goto done; for (i = 0; i < list->num; i++) { uint8_t *value = list->data[i]; int j; char_data->start = att_get_u16(value) + 1; g_print("handle: 0x%04x \t value: ", att_get_u16(value)); value += 2; for (j = 0; j < list->len - 2; j++, value++) g_print("%02x ", *value); g_print("\n"); } att_data_list_free(list); done: g_free(char_data); g_main_loop_quit(event_loop); } static gboolean characteristics_read(gpointer user_data) { GAttrib *attrib = user_data; if (opt_uuid != NULL) { struct characteristic_data *char_data; char_data = g_new(struct characteristic_data, 1); char_data->attrib = attrib; char_data->start = opt_start; char_data->end = opt_end; gatt_read_char_by_uuid(attrib, opt_start, opt_end, opt_uuid, char_read_by_uuid_cb, char_data); return FALSE; } if (opt_handle <= 0) { g_printerr("A valid handle is required\n"); g_main_loop_quit(event_loop); return FALSE; } gatt_read_char(attrib, opt_handle, opt_offset, char_read_cb, attrib); return FALSE; } static void mainloop_quit(gpointer user_data) { uint8_t *value = user_data; g_free(value); g_main_loop_quit(event_loop); } static gboolean characteristics_write(gpointer user_data) { GAttrib *attrib = user_data; uint8_t *value; size_t len; if (opt_handle <= 0) { g_printerr("A valid handle is required\n"); goto error; } if (opt_value == NULL || opt_value[0] == '\0') { g_printerr("A value is required\n"); goto error; } len = gatt_attr_data_from_string(opt_value, &value); if (len == 0) { g_printerr("Invalid value\n"); goto error; } gatt_write_cmd(attrib, opt_handle, value, len, mainloop_quit, value); return FALSE; error: g_main_loop_quit(event_loop); return FALSE; } static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { if (status != 0) { g_printerr("Characteristic Write Request failed: " "%s\n", att_ecode2str(status)); goto done; } if (!dec_write_resp(pdu, plen)) { g_printerr("Protocol error\n"); goto done; } g_print("Characteristic value was written successfully\n"); done: if (opt_listen == FALSE) g_main_loop_quit(event_loop); } static gboolean characteristics_write_req(gpointer user_data) { GAttrib *attrib = user_data; uint8_t *value; size_t len; if (opt_handle <= 0) { g_printerr("A valid handle is required\n"); goto error; } if (opt_value == NULL || opt_value[0] == '\0') { g_printerr("A value is required\n"); goto error; } len = gatt_attr_data_from_string(opt_value, &value); if (len == 0) { g_printerr("Invalid value\n"); goto error; } gatt_write_char(attrib, opt_handle, value, len, char_write_req_cb, NULL); return FALSE; error: g_main_loop_quit(event_loop); return FALSE; } static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct att_data_list *list; guint8 format; int i; if (status != 0) { g_printerr("Discover all characteristic descriptors failed: " "%s\n", att_ecode2str(status)); goto done; } list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) goto done; for (i = 0; i < list->num; i++) { char uuidstr[MAX_LEN_UUID_STR]; uint16_t handle; uint8_t *value; bt_uuid_t uuid; value = list->data[i]; handle = att_get_u16(value); if (format == 0x01) uuid = att_get_uuid16(&value[2]); else uuid = att_get_uuid128(&value[2]); bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR); g_print("handle = 0x%04x, uuid = %s\n", handle, uuidstr); } att_data_list_free(list); done: if (opt_listen == FALSE) g_main_loop_quit(event_loop); } static gboolean characteristics_desc(gpointer user_data) { GAttrib *attrib = user_data; gatt_find_info(attrib, opt_start, opt_end, char_desc_cb, NULL); return FALSE; } static gboolean parse_uuid(const char *key, const char *value, gpointer user_data, GError **error) { if (!value) return FALSE; opt_uuid = g_try_malloc(sizeof(bt_uuid_t)); if (opt_uuid == NULL) return FALSE; if (bt_string_to_uuid(opt_uuid, value) < 0) return FALSE; return TRUE; } static GOptionEntry primary_char_options[] = { { "start", 's' , 0, G_OPTION_ARG_INT, &opt_start, "Starting handle(optional)", "0x0001" }, { "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end, "Ending handle(optional)", "0xffff" }, { "uuid", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_uuid, "UUID16 or UUID128(optional)", "0x1801"}, { NULL }, }; static GOptionEntry char_rw_options[] = { { "handle", 'a' , 0, G_OPTION_ARG_INT, &opt_handle, "Read/Write characteristic by handle(required)", "0x0001" }, { "value", 'n' , 0, G_OPTION_ARG_STRING, &opt_value, "Write characteristic value (required for write operation)", "0x0001" }, { "offset", 'o', 0, G_OPTION_ARG_INT, &opt_offset, "Offset to long read characteristic by handle", "N"}, {NULL}, }; static GOptionEntry gatt_options[] = { { "primary", 0, 0, G_OPTION_ARG_NONE, &opt_primary, "Primary Service Discovery", NULL }, { "characteristics", 0, 0, G_OPTION_ARG_NONE, &opt_characteristics, "Characteristics Discovery", NULL }, { "char-read", 0, 0, G_OPTION_ARG_NONE, &opt_char_read, "Characteristics Value/Descriptor Read", NULL }, { "char-write", 0, 0, G_OPTION_ARG_NONE, &opt_char_write, "Characteristics Value Write Without Response (Write Command)", NULL }, { "char-write-req", 0, 0, G_OPTION_ARG_NONE, &opt_char_write_req, "Characteristics Value Write (Write Request)", NULL }, { "char-desc", 0, 0, G_OPTION_ARG_NONE, &opt_char_desc, "Characteristics Descriptor Discovery", NULL }, { "listen", 0, 0, G_OPTION_ARG_NONE, &opt_listen, "Listen for notifications and indications", NULL }, { "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE, &opt_interactive, "Use interactive mode", NULL }, { NULL }, }; static GOptionEntry options[] = { { "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src, "Specify local adapter interface", "hciX" }, { "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst, "Specify remote Bluetooth address", "MAC" }, { "addr-type", 't', 0, G_OPTION_ARG_STRING, &opt_dst_type, "Set LE address type. Default: public", "[public | random]"}, { "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu, "Specify the MTU size", "MTU" }, { "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm, "Specify the PSM for GATT/ATT over BR/EDR", "PSM" }, { "sec-level", 'l', 0, G_OPTION_ARG_STRING, &opt_sec_level, "Set security level. Default: low", "[low | medium | high]"}, { NULL }, }; int main(int argc, char *argv[]) { GOptionContext *context; GOptionGroup *gatt_group, *params_group, *char_rw_group; GError *gerr = NULL; GIOChannel *chan; opt_dst_type = g_strdup("public"); opt_sec_level = g_strdup("low"); context = g_option_context_new(NULL); g_option_context_add_main_entries(context, options, NULL); /* GATT commands */ gatt_group = g_option_group_new("gatt", "GATT commands", "Show all GATT commands", NULL, NULL); g_option_context_add_group(context, gatt_group); g_option_group_add_entries(gatt_group, gatt_options); /* Primary Services and Characteristics arguments */ params_group = g_option_group_new("params", "Primary Services/Characteristics arguments", "Show all Primary Services/Characteristics arguments", NULL, NULL); g_option_context_add_group(context, params_group); g_option_group_add_entries(params_group, primary_char_options); /* Characteristics value/descriptor read/write arguments */ char_rw_group = g_option_group_new("char-read-write", "Characteristics Value/Descriptor Read/Write arguments", "Show all Characteristics Value/Descriptor Read/Write " "arguments", NULL, NULL); g_option_context_add_group(context, char_rw_group); g_option_group_add_entries(char_rw_group, char_rw_options); if (g_option_context_parse(context, &argc, &argv, &gerr) == FALSE) { g_printerr("%s\n", gerr->message); g_error_free(gerr); } if (opt_interactive) { interactive(opt_src, opt_dst, opt_dst_type, opt_psm); goto done; } if (opt_primary) operation = primary; else if (opt_characteristics) operation = characteristics; else if (opt_char_read) operation = characteristics_read; else if (opt_char_write) operation = characteristics_write; else if (opt_char_write_req) operation = characteristics_write_req; else if (opt_char_desc) operation = characteristics_desc; else { gchar *help = g_option_context_get_help(context, TRUE, NULL); g_print("%s\n", help); g_free(help); got_error = TRUE; goto done; } chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level, opt_psm, opt_mtu, connect_cb); if (chan == NULL) { got_error = TRUE; goto done; } event_loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(event_loop); g_main_loop_unref(event_loop); done: g_option_context_free(context); g_free(opt_src); g_free(opt_dst); g_free(opt_uuid); g_free(opt_sec_level); if (got_error) exit(EXIT_FAILURE); else exit(EXIT_SUCCESS); } bluez-4.101/attrib/gattrib.c0000644000000000000000000003321011766125764012632 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include "log.h" #include "att.h" #include "btio.h" #include "gattrib.h" #define GATT_TIMEOUT 30 struct _GAttrib { GIOChannel *io; gint refs; uint8_t *buf; int buflen; guint read_watch; guint write_watch; guint timeout_watch; GQueue *requests; GQueue *responses; GSList *events; guint next_cmd_id; GDestroyNotify destroy; gpointer destroy_user_data; gboolean stale; }; struct command { guint id; guint8 opcode; guint8 *pdu; guint16 len; guint8 expected; gboolean sent; GAttribResultFunc func; gpointer user_data; GDestroyNotify notify; }; struct event { guint id; guint8 expected; GAttribNotifyFunc func; gpointer user_data; GDestroyNotify notify; }; static guint8 opcode2expected(guint8 opcode) { switch (opcode) { case ATT_OP_MTU_REQ: return ATT_OP_MTU_RESP; case ATT_OP_FIND_INFO_REQ: return ATT_OP_FIND_INFO_RESP; case ATT_OP_FIND_BY_TYPE_REQ: return ATT_OP_FIND_BY_TYPE_RESP; case ATT_OP_READ_BY_TYPE_REQ: return ATT_OP_READ_BY_TYPE_RESP; case ATT_OP_READ_REQ: return ATT_OP_READ_RESP; case ATT_OP_READ_BLOB_REQ: return ATT_OP_READ_BLOB_RESP; case ATT_OP_READ_MULTI_REQ: return ATT_OP_READ_MULTI_RESP; case ATT_OP_READ_BY_GROUP_REQ: return ATT_OP_READ_BY_GROUP_RESP; case ATT_OP_WRITE_REQ: return ATT_OP_WRITE_RESP; case ATT_OP_PREP_WRITE_REQ: return ATT_OP_PREP_WRITE_RESP; case ATT_OP_EXEC_WRITE_REQ: return ATT_OP_EXEC_WRITE_RESP; case ATT_OP_HANDLE_IND: return ATT_OP_HANDLE_CNF; } return 0; } static gboolean is_response(guint8 opcode) { switch (opcode) { case ATT_OP_ERROR: case ATT_OP_MTU_RESP: case ATT_OP_FIND_INFO_RESP: case ATT_OP_FIND_BY_TYPE_RESP: case ATT_OP_READ_BY_TYPE_RESP: case ATT_OP_READ_RESP: case ATT_OP_READ_BLOB_RESP: case ATT_OP_READ_MULTI_RESP: case ATT_OP_READ_BY_GROUP_RESP: case ATT_OP_WRITE_RESP: case ATT_OP_PREP_WRITE_RESP: case ATT_OP_EXEC_WRITE_RESP: case ATT_OP_HANDLE_CNF: return TRUE; } return FALSE; } GAttrib *g_attrib_ref(GAttrib *attrib) { if (!attrib) return NULL; g_atomic_int_inc(&attrib->refs); DBG("%p: ref=%d", attrib, attrib->refs); return attrib; } static void command_destroy(struct command *cmd) { if (cmd->notify) cmd->notify(cmd->user_data); g_free(cmd->pdu); g_free(cmd); } static void event_destroy(struct event *evt) { if (evt->notify) evt->notify(evt->user_data); g_free(evt); } static void attrib_destroy(GAttrib *attrib) { GSList *l; struct command *c; while ((c = g_queue_pop_head(attrib->requests))) command_destroy(c); while ((c = g_queue_pop_head(attrib->responses))) command_destroy(c); g_queue_free(attrib->requests); attrib->requests = NULL; g_queue_free(attrib->responses); attrib->responses = NULL; for (l = attrib->events; l; l = l->next) event_destroy(l->data); g_slist_free(attrib->events); attrib->events = NULL; if (attrib->timeout_watch > 0) g_source_remove(attrib->timeout_watch); if (attrib->write_watch > 0) g_source_remove(attrib->write_watch); if (attrib->read_watch > 0) g_source_remove(attrib->read_watch); if (attrib->io) g_io_channel_unref(attrib->io); g_free(attrib->buf); if (attrib->destroy) attrib->destroy(attrib->destroy_user_data); g_free(attrib); } void g_attrib_unref(GAttrib *attrib) { gboolean ret; if (!attrib) return; ret = g_atomic_int_dec_and_test(&attrib->refs); DBG("%p: ref=%d", attrib, attrib->refs); if (ret == FALSE) return; attrib_destroy(attrib); } GIOChannel *g_attrib_get_channel(GAttrib *attrib) { if (!attrib) return NULL; return attrib->io; } gboolean g_attrib_set_destroy_function(GAttrib *attrib, GDestroyNotify destroy, gpointer user_data) { if (attrib == NULL) return FALSE; attrib->destroy = destroy; attrib->destroy_user_data = user_data; return TRUE; } static gboolean disconnect_timeout(gpointer data) { struct _GAttrib *attrib = data; struct command *c; g_attrib_ref(attrib); c = g_queue_pop_head(attrib->requests); if (c == NULL) goto done; if (c->func) c->func(ATT_ECODE_TIMEOUT, NULL, 0, c->user_data); command_destroy(c); while ((c = g_queue_pop_head(attrib->requests))) { if (c->func) c->func(ATT_ECODE_ABORTED, NULL, 0, c->user_data); command_destroy(c); } done: attrib->stale = TRUE; g_attrib_unref(attrib); return FALSE; } static gboolean can_write_data(GIOChannel *io, GIOCondition cond, gpointer data) { struct _GAttrib *attrib = data; struct command *cmd; GError *gerr = NULL; gsize len; GIOStatus iostat; GQueue *queue; if (attrib->stale) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) return FALSE; queue = attrib->responses; cmd = g_queue_peek_head(queue); if (cmd == NULL) { queue = attrib->requests; cmd = g_queue_peek_head(queue); } if (cmd == NULL) return FALSE; /* * Verify that we didn't already send this command. This can only * happen with elementes from attrib->requests. */ if (cmd->sent) return FALSE; iostat = g_io_channel_write_chars(io, (gchar *) cmd->pdu, cmd->len, &len, &gerr); if (iostat != G_IO_STATUS_NORMAL) return FALSE; if (cmd->expected == 0) { g_queue_pop_head(queue); command_destroy(cmd); return TRUE; } cmd->sent = TRUE; if (attrib->timeout_watch == 0) attrib->timeout_watch = g_timeout_add_seconds(GATT_TIMEOUT, disconnect_timeout, attrib); return FALSE; } static void destroy_sender(gpointer data) { struct _GAttrib *attrib = data; attrib->write_watch = 0; g_attrib_unref(attrib); } static void wake_up_sender(struct _GAttrib *attrib) { if (attrib->write_watch > 0) return; attrib = g_attrib_ref(attrib); attrib->write_watch = g_io_add_watch_full(attrib->io, G_PRIORITY_DEFAULT, G_IO_OUT, can_write_data, attrib, destroy_sender); } static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data) { struct _GAttrib *attrib = data; struct command *cmd = NULL; GSList *l; uint8_t buf[512], status; gsize len; GIOStatus iostat; gboolean norequests, noresponses; if (attrib->stale) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { attrib->read_watch = 0; return FALSE; } memset(buf, 0, sizeof(buf)); iostat = g_io_channel_read_chars(io, (gchar *) buf, sizeof(buf), &len, NULL); if (iostat != G_IO_STATUS_NORMAL) { status = ATT_ECODE_IO; goto done; } for (l = attrib->events; l; l = l->next) { struct event *evt = l->data; if (evt->expected == buf[0] || evt->expected == GATTRIB_ALL_EVENTS || (is_response(buf[0]) == FALSE && evt->expected == GATTRIB_ALL_REQS)) evt->func(buf, len, evt->user_data); } if (is_response(buf[0]) == FALSE) return TRUE; if (attrib->timeout_watch > 0) { g_source_remove(attrib->timeout_watch); attrib->timeout_watch = 0; } cmd = g_queue_pop_head(attrib->requests); if (cmd == NULL) { /* Keep the watch if we have events to report */ return attrib->events != NULL; } if (buf[0] == ATT_OP_ERROR) { status = buf[4]; goto done; } if (cmd->expected != buf[0]) { status = ATT_ECODE_IO; goto done; } status = 0; done: norequests = attrib->requests == NULL || g_queue_is_empty(attrib->requests); noresponses = attrib->responses == NULL || g_queue_is_empty(attrib->responses); if (cmd) { if (cmd->func) cmd->func(status, buf, len, cmd->user_data); command_destroy(cmd); } if (!norequests || !noresponses) wake_up_sender(attrib); return TRUE; } GAttrib *g_attrib_new(GIOChannel *io) { struct _GAttrib *attrib; uint16_t imtu; uint16_t att_mtu; uint16_t cid; GError *gerr = NULL; g_io_channel_set_encoding(io, NULL, NULL); g_io_channel_set_buffered(io, FALSE); bt_io_get(io, BT_IO_L2CAP, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); return NULL; } attrib = g_try_new0(struct _GAttrib, 1); if (attrib == NULL) return NULL; att_mtu = (cid == ATT_CID) ? ATT_DEFAULT_LE_MTU : imtu; attrib->buf = g_malloc0(att_mtu); attrib->buflen = att_mtu; attrib->io = g_io_channel_ref(io); attrib->requests = g_queue_new(); attrib->responses = g_queue_new(); attrib->read_watch = g_io_add_watch(attrib->io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, received_data, attrib); return g_attrib_ref(attrib); } guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode, const guint8 *pdu, guint16 len, GAttribResultFunc func, gpointer user_data, GDestroyNotify notify) { struct command *c; GQueue *queue; if (attrib->stale) return 0; c = g_try_new0(struct command, 1); if (c == NULL) return 0; c->opcode = opcode; c->expected = opcode2expected(opcode); c->pdu = g_malloc(len); memcpy(c->pdu, pdu, len); c->len = len; c->func = func; c->user_data = user_data; c->notify = notify; if (is_response(opcode)) queue = attrib->responses; else queue = attrib->requests; if (id) { c->id = id; if (!is_response(opcode)) g_queue_push_head(queue, c); else /* Don't re-order responses even if an ID is given */ g_queue_push_tail(queue, c); } else { c->id = ++attrib->next_cmd_id; g_queue_push_tail(queue, c); } /* * If a command was added to the queue and it was empty before, wake up * the sender. If the sender was already woken up by the second queue, * wake_up_sender will just return. */ if (g_queue_get_length(queue) == 1) wake_up_sender(attrib); return c->id; } static gint command_cmp_by_id(gconstpointer a, gconstpointer b) { const struct command *cmd = a; guint id = GPOINTER_TO_UINT(b); return cmd->id - id; } gboolean g_attrib_cancel(GAttrib *attrib, guint id) { GList *l = NULL; struct command *cmd; GQueue *queue; if (attrib == NULL) return FALSE; queue = attrib->requests; if (queue) l = g_queue_find_custom(queue, GUINT_TO_POINTER(id), command_cmp_by_id); if (l == NULL) { queue = attrib->responses; if (!queue) return FALSE; l = g_queue_find_custom(queue, GUINT_TO_POINTER(id), command_cmp_by_id); } if (l == NULL) return FALSE; cmd = l->data; if (cmd == g_queue_peek_head(queue) && cmd->sent) cmd->func = NULL; else { g_queue_remove(queue, cmd); command_destroy(cmd); } return TRUE; } static gboolean cancel_all_per_queue(GQueue *queue) { struct command *c, *head = NULL; gboolean first = TRUE; if (queue == NULL) return FALSE; while ((c = g_queue_pop_head(queue))) { if (first && c->sent) { /* If the command was sent ignore its callback ... */ c->func = NULL; head = c; continue; } first = FALSE; command_destroy(c); } if (head) { /* ... and put it back in the queue */ g_queue_push_head(queue, head); } return TRUE; } gboolean g_attrib_cancel_all(GAttrib *attrib) { gboolean ret; if (attrib == NULL) return FALSE; ret = cancel_all_per_queue(attrib->requests); ret = cancel_all_per_queue(attrib->responses) && ret; return ret; } gboolean g_attrib_set_debug(GAttrib *attrib, GAttribDebugFunc func, gpointer user_data) { return TRUE; } uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len) { if (len == NULL) return NULL; *len = attrib->buflen; return attrib->buf; } gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu) { if (mtu < ATT_DEFAULT_LE_MTU) return FALSE; attrib->buf = g_realloc(attrib->buf, mtu); attrib->buflen = mtu; return TRUE; } guint g_attrib_register(GAttrib *attrib, guint8 opcode, GAttribNotifyFunc func, gpointer user_data, GDestroyNotify notify) { static guint next_evt_id = 0; struct event *event; event = g_try_new0(struct event, 1); if (event == NULL) return 0; event->expected = opcode; event->func = func; event->user_data = user_data; event->notify = notify; event->id = ++next_evt_id; attrib->events = g_slist_append(attrib->events, event); return event->id; } static gint event_cmp_by_id(gconstpointer a, gconstpointer b) { const struct event *evt = a; guint id = GPOINTER_TO_UINT(b); return evt->id - id; } gboolean g_attrib_is_encrypted(GAttrib *attrib) { BtIOSecLevel sec_level; if (!bt_io_get(attrib->io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, &sec_level, BT_IO_OPT_INVALID)) return FALSE; return sec_level > BT_IO_SEC_LOW; } gboolean g_attrib_unregister(GAttrib *attrib, guint id) { struct event *evt; GSList *l; l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id), event_cmp_by_id); if (l == NULL) return FALSE; evt = l->data; attrib->events = g_slist_remove(attrib->events, evt); if (evt->notify) evt->notify(evt->user_data); g_free(evt); return TRUE; } gboolean g_attrib_unregister_all(GAttrib *attrib) { GSList *l; if (attrib->events == NULL) return FALSE; for (l = attrib->events; l; l = l->next) { struct event *evt = l->data; if (evt->notify) evt->notify(evt->user_data); g_free(evt); } g_slist_free(attrib->events); attrib->events = NULL; return TRUE; } bluez-4.101/attrib/gatttool.h0000644000000000000000000000220111766125764013034 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int interactive(const gchar *src, const gchar *dst, const gchar *dst_type, gboolean le); GIOChannel *gatt_connect(const gchar *src, const gchar *dst, const gchar *dst_type, const gchar *sec_level, int psm, int mtu, BtIOConnect connect_cb); size_t gatt_attr_data_from_string(const char *str, uint8_t **data); bluez-4.101/attrib/att-database.h0000644000000000000000000000261211766125764013537 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2012 Texas Instruments Corporation * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* Requirements for read/write operations */ enum { ATT_NONE, /* No restrictions */ ATT_AUTHENTICATION, /* Authentication required */ ATT_AUTHORIZATION, /* Authorization required */ ATT_NOT_PERMITTED, /* Operation not permitted */ }; struct attribute { uint16_t handle; bt_uuid_t uuid; int read_reqs; int write_reqs; uint8_t (*read_cb)(struct attribute *a, struct btd_device *device, gpointer user_data); uint8_t (*write_cb)(struct attribute *a, struct btd_device *device, gpointer user_data); gpointer cb_user_data; int len; uint8_t *data; }; bluez-4.101/attrib/interactive.c0000644000000000000000000004430711766125764013524 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include #include #include "att.h" #include "btio.h" #include "gattrib.h" #include "gatt.h" #include "gatttool.h" static GIOChannel *iochannel = NULL; static GAttrib *attrib = NULL; static GMainLoop *event_loop; static GString *prompt; static gchar *opt_src = NULL; static gchar *opt_dst = NULL; static gchar *opt_dst_type = NULL; static gchar *opt_sec_level = NULL; static int opt_psm = 0; static int opt_mtu = 0; struct characteristic_data { uint16_t orig_start; uint16_t start; uint16_t end; bt_uuid_t uuid; }; static void cmd_help(int argcp, char **argvp); enum state { STATE_DISCONNECTED, STATE_CONNECTING, STATE_CONNECTED } conn_state; static char *get_prompt(void) { if (conn_state == STATE_CONNECTING) { g_string_assign(prompt, "Connecting... "); return prompt->str; } if (conn_state == STATE_CONNECTED) g_string_assign(prompt, "[CON]"); else g_string_assign(prompt, "[ ]"); if (opt_dst) g_string_append_printf(prompt, "[%17s]", opt_dst); else g_string_append_printf(prompt, "[%17s]", ""); if (opt_psm) g_string_append(prompt, "[BR]"); else g_string_append(prompt, "[LE]"); g_string_append(prompt, "> "); return prompt->str; } static void set_state(enum state st) { conn_state = st; rl_set_prompt(get_prompt()); rl_redisplay(); } static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data) { uint8_t opdu[ATT_MAX_MTU]; uint16_t handle, i, olen; handle = att_get_u16(&pdu[1]); printf("\n"); switch (pdu[0]) { case ATT_OP_HANDLE_NOTIFY: printf("Notification handle = 0x%04x value: ", handle); break; case ATT_OP_HANDLE_IND: printf("Indication handle = 0x%04x value: ", handle); break; default: printf("Invalid opcode\n"); return; } for (i = 3; i < len; i++) printf("%02x ", pdu[i]); printf("\n"); rl_forced_update_display(); if (pdu[0] == ATT_OP_HANDLE_NOTIFY) return; olen = enc_confirmation(opdu, sizeof(opdu)); if (olen > 0) g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL); } static void connect_cb(GIOChannel *io, GError *err, gpointer user_data) { if (err) { printf("connect error: %s\n", err->message); set_state(STATE_DISCONNECTED); return; } attrib = g_attrib_new(iochannel); g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, events_handler, attrib, NULL); g_attrib_register(attrib, ATT_OP_HANDLE_IND, events_handler, attrib, NULL); set_state(STATE_CONNECTED); } static void disconnect_io() { if (conn_state == STATE_DISCONNECTED) return; g_attrib_unref(attrib); attrib = NULL; opt_mtu = 0; g_io_channel_shutdown(iochannel, FALSE, NULL); g_io_channel_unref(iochannel); iochannel = NULL; set_state(STATE_DISCONNECTED); } static void primary_all_cb(GSList *services, guint8 status, gpointer user_data) { GSList *l; if (status) { printf("Discover all primary services failed: %s\n", att_ecode2str(status)); return; } printf("\n"); for (l = services; l; l = l->next) { struct gatt_primary *prim = l->data; printf("attr handle: 0x%04x, end grp handle: 0x%04x " "uuid: %s\n", prim->range.start, prim->range.end, prim->uuid); } rl_forced_update_display(); } static void primary_by_uuid_cb(GSList *ranges, guint8 status, gpointer user_data) { GSList *l; if (status) { printf("Discover primary services by UUID failed: %s\n", att_ecode2str(status)); return; } printf("\n"); for (l = ranges; l; l = l->next) { struct att_range *range = l->data; g_print("Starting handle: 0x%04x Ending handle: 0x%04x\n", range->start, range->end); } rl_forced_update_display(); } static void char_cb(GSList *characteristics, guint8 status, gpointer user_data) { GSList *l; if (status) { printf("Discover all characteristics failed: %s\n", att_ecode2str(status)); return; } printf("\n"); for (l = characteristics; l; l = l->next) { struct gatt_char *chars = l->data; printf("handle: 0x%04x, char properties: 0x%02x, char value " "handle: 0x%04x, uuid: %s\n", chars->handle, chars->properties, chars->value_handle, chars->uuid); } rl_forced_update_display(); } static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct att_data_list *list; guint8 format; int i; if (status != 0) { printf("Discover all characteristic descriptors failed: " "%s\n", att_ecode2str(status)); return; } list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) return; printf("\n"); for (i = 0; i < list->num; i++) { char uuidstr[MAX_LEN_UUID_STR]; uint16_t handle; uint8_t *value; bt_uuid_t uuid; value = list->data[i]; handle = att_get_u16(value); if (format == 0x01) uuid = att_get_uuid16(&value[2]); else uuid = att_get_uuid128(&value[2]); bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR); printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr); } att_data_list_free(list); rl_forced_update_display(); } static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { uint8_t value[ATT_MAX_MTU]; int i, vlen; if (status != 0) { printf("Characteristic value/descriptor read failed: %s\n", att_ecode2str(status)); return; } if (!dec_read_resp(pdu, plen, value, &vlen)) { printf("Protocol error\n"); return; } printf("\nCharacteristic value/descriptor: "); for (i = 0; i < vlen; i++) printf("%02x ", value[i]); printf("\n"); rl_forced_update_display(); } static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct characteristic_data *char_data = user_data; struct att_data_list *list; int i; if (status == ATT_ECODE_ATTR_NOT_FOUND && char_data->start != char_data->orig_start) goto done; if (status != 0) { printf("Read characteristics by UUID failed: %s\n", att_ecode2str(status)); goto done; } list = dec_read_by_type_resp(pdu, plen); if (list == NULL) goto done; for (i = 0; i < list->num; i++) { uint8_t *value = list->data[i]; int j; char_data->start = att_get_u16(value) + 1; printf("\nhandle: 0x%04x \t value: ", att_get_u16(value)); value += 2; for (j = 0; j < list->len - 2; j++, value++) printf("%02x ", *value); printf("\n"); } att_data_list_free(list); rl_forced_update_display(); done: g_free(char_data); } static void cmd_exit(int argcp, char **argvp) { rl_callback_handler_remove(); g_main_loop_quit(event_loop); } static gboolean channel_watcher(GIOChannel *chan, GIOCondition cond, gpointer user_data) { disconnect_io(); return FALSE; } static void cmd_connect(int argcp, char **argvp) { if (conn_state != STATE_DISCONNECTED) return; if (argcp > 1) { g_free(opt_dst); opt_dst = g_strdup(argvp[1]); g_free(opt_dst_type); if (argcp > 2) opt_dst_type = g_strdup(argvp[2]); else opt_dst_type = g_strdup("public"); } if (opt_dst == NULL) { printf("Remote Bluetooth address required\n"); return; } set_state(STATE_CONNECTING); iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level, opt_psm, opt_mtu, connect_cb); if (iochannel == NULL) set_state(STATE_DISCONNECTED); else g_io_add_watch(iochannel, G_IO_HUP, channel_watcher, NULL); } static void cmd_disconnect(int argcp, char **argvp) { disconnect_io(); } static void cmd_primary(int argcp, char **argvp) { bt_uuid_t uuid; if (conn_state != STATE_CONNECTED) { printf("Command failed: disconnected\n"); return; } if (argcp == 1) { gatt_discover_primary(attrib, NULL, primary_all_cb, NULL); return; } if (bt_string_to_uuid(&uuid, argvp[1]) < 0) { printf("Invalid UUID\n"); return; } gatt_discover_primary(attrib, &uuid, primary_by_uuid_cb, NULL); } static int strtohandle(const char *src) { char *e; int dst; errno = 0; dst = strtoll(src, &e, 16); if (errno != 0 || *e != '\0') return -EINVAL; return dst; } static void cmd_char(int argcp, char **argvp) { int start = 0x0001; int end = 0xffff; if (conn_state != STATE_CONNECTED) { printf("Command failed: disconnected\n"); return; } if (argcp > 1) { start = strtohandle(argvp[1]); if (start < 0) { printf("Invalid start handle: %s\n", argvp[1]); return; } } if (argcp > 2) { end = strtohandle(argvp[2]); if (end < 0) { printf("Invalid end handle: %s\n", argvp[2]); return; } } if (argcp > 3) { bt_uuid_t uuid; if (bt_string_to_uuid(&uuid, argvp[3]) < 0) { printf("Invalid UUID\n"); return; } gatt_discover_char(attrib, start, end, &uuid, char_cb, NULL); return; } gatt_discover_char(attrib, start, end, NULL, char_cb, NULL); } static void cmd_char_desc(int argcp, char **argvp) { int start = 0x0001; int end = 0xffff; if (conn_state != STATE_CONNECTED) { printf("Command failed: disconnected\n"); return; } if (argcp > 1) { start = strtohandle(argvp[1]); if (start < 0) { printf("Invalid start handle: %s\n", argvp[1]); return; } } if (argcp > 2) { end = strtohandle(argvp[2]); if (end < 0) { printf("Invalid end handle: %s\n", argvp[2]); return; } } gatt_find_info(attrib, start, end, char_desc_cb, NULL); } static void cmd_read_hnd(int argcp, char **argvp) { int handle; int offset = 0; if (conn_state != STATE_CONNECTED) { printf("Command failed: disconnected\n"); return; } if (argcp < 2) { printf("Missing argument: handle\n"); return; } handle = strtohandle(argvp[1]); if (handle < 0) { printf("Invalid handle: %s\n", argvp[1]); return; } if (argcp > 2) { char *e; errno = 0; offset = strtol(argvp[2], &e, 0); if (errno != 0 || *e != '\0') { printf("Invalid offset: %s\n", argvp[2]); return; } } gatt_read_char(attrib, handle, offset, char_read_cb, attrib); } static void cmd_read_uuid(int argcp, char **argvp) { struct characteristic_data *char_data; int start = 0x0001; int end = 0xffff; bt_uuid_t uuid; if (conn_state != STATE_CONNECTED) { printf("Command failed: disconnected\n"); return; } if (argcp < 2) { printf("Missing argument: UUID\n"); return; } if (bt_string_to_uuid(&uuid, argvp[1]) < 0) { printf("Invalid UUID\n"); return; } if (argcp > 2) { start = strtohandle(argvp[2]); if (start < 0) { printf("Invalid start handle: %s\n", argvp[1]); return; } } if (argcp > 3) { end = strtohandle(argvp[3]); if (end < 0) { printf("Invalid end handle: %s\n", argvp[2]); return; } } char_data = g_new(struct characteristic_data, 1); char_data->orig_start = start; char_data->start = start; char_data->end = end; char_data->uuid = uuid; gatt_read_char_by_uuid(attrib, start, end, &char_data->uuid, char_read_by_uuid_cb, char_data); } static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { if (status != 0) { printf("Characteristic Write Request failed: " "%s\n", att_ecode2str(status)); return; } if (!dec_write_resp(pdu, plen)) { printf("Protocol error\n"); return; } printf("Characteristic value was written successfully\n"); } static void cmd_char_write(int argcp, char **argvp) { uint8_t *value; size_t plen; int handle; if (conn_state != STATE_CONNECTED) { printf("Command failed: disconnected\n"); return; } if (argcp < 3) { printf("Usage: %s \n", argvp[0]); return; } handle = strtohandle(argvp[1]); if (handle <= 0) { printf("A valid handle is required\n"); return; } plen = gatt_attr_data_from_string(argvp[2], &value); if (plen == 0) { g_printerr("Invalid value\n"); return; } if (g_strcmp0("char-write-req", argvp[0]) == 0) gatt_write_char(attrib, handle, value, plen, char_write_req_cb, NULL); else gatt_write_char(attrib, handle, value, plen, NULL, NULL); g_free(value); } static void cmd_sec_level(int argcp, char **argvp) { GError *gerr = NULL; BtIOSecLevel sec_level; if (argcp < 2) { printf("sec-level: %s\n", opt_sec_level); return; } if (strcasecmp(argvp[1], "medium") == 0) sec_level = BT_IO_SEC_MEDIUM; else if (strcasecmp(argvp[1], "high") == 0) sec_level = BT_IO_SEC_HIGH; else if (strcasecmp(argvp[1], "low") == 0) sec_level = BT_IO_SEC_LOW; else { printf("Allowed values: low | medium | high\n"); return; } g_free(opt_sec_level); opt_sec_level = g_strdup(argvp[1]); if (conn_state != STATE_CONNECTED) return; if (opt_psm) { printf("It must be reconnected to this change take effect\n"); return; } bt_io_set(iochannel, BT_IO_L2CAP, &gerr, BT_IO_OPT_SEC_LEVEL, sec_level, BT_IO_OPT_INVALID); if (gerr) { printf("Error: %s\n", gerr->message); g_error_free(gerr); } } static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { uint16_t mtu; if (status != 0) { printf("Exchange MTU Request failed: %s\n", att_ecode2str(status)); return; } if (!dec_mtu_resp(pdu, plen, &mtu)) { printf("Protocol error\n"); return; } mtu = MIN(mtu, opt_mtu); /* Set new value for MTU in client */ if (g_attrib_set_mtu(attrib, mtu)) printf("MTU was exchanged successfully: %d\n", mtu); else printf("Error exchanging MTU\n"); } static void cmd_mtu(int argcp, char **argvp) { if (conn_state != STATE_CONNECTED) { printf("Command failed: not connected.\n"); return; } if (opt_psm) { printf("Command failed: operation is only available for LE" " transport.\n"); return; } if (argcp < 2) { printf("Usage: mtu \n"); return; } if (opt_mtu) { printf("Command failed: MTU exchange can only occur once per" " connection.\n"); return; } errno = 0; opt_mtu = strtoll(argvp[1], NULL, 0); if (errno != 0 || opt_mtu < ATT_DEFAULT_LE_MTU) { printf("Invalid value. Minimum MTU size is %d\n", ATT_DEFAULT_LE_MTU); return; } gatt_exchange_mtu(attrib, opt_mtu, exchange_mtu_cb, NULL); } static struct { const char *cmd; void (*func)(int argcp, char **argvp); const char *params; const char *desc; } commands[] = { { "help", cmd_help, "", "Show this help"}, { "exit", cmd_exit, "", "Exit interactive mode" }, { "quit", cmd_exit, "", "Exit interactive mode" }, { "connect", cmd_connect, "[address [address type]]", "Connect to a remote device" }, { "disconnect", cmd_disconnect, "", "Disconnect from a remote device" }, { "primary", cmd_primary, "[UUID]", "Primary Service Discovery" }, { "characteristics", cmd_char, "[start hnd [end hnd [UUID]]]", "Characteristics Discovery" }, { "char-desc", cmd_char_desc, "[start hnd] [end hnd]", "Characteristics Descriptor Discovery" }, { "char-read-hnd", cmd_read_hnd, " [offset]", "Characteristics Value/Descriptor Read by handle" }, { "char-read-uuid", cmd_read_uuid, " [start hnd] [end hnd]", "Characteristics Value/Descriptor Read by UUID" }, { "char-write-req", cmd_char_write, " ", "Characteristic Value Write (Write Request)" }, { "char-write-cmd", cmd_char_write, " ", "Characteristic Value Write (No response)" }, { "sec-level", cmd_sec_level, "[low | medium | high]", "Set security level. Default: low" }, { "mtu", cmd_mtu, "", "Exchange MTU for GATT/ATT" }, { NULL, NULL, NULL} }; static void cmd_help(int argcp, char **argvp) { int i; for (i = 0; commands[i].cmd; i++) printf("%-15s %-30s %s\n", commands[i].cmd, commands[i].params, commands[i].desc); } static void parse_line(char *line_read) { gchar **argvp; int argcp; int i; if (line_read == NULL) { printf("\n"); cmd_exit(0, NULL); return; } line_read = g_strstrip(line_read); if (*line_read == '\0') return; add_history(line_read); g_shell_parse_argv(line_read, &argcp, &argvp, NULL); for (i = 0; commands[i].cmd; i++) if (strcasecmp(commands[i].cmd, argvp[0]) == 0) break; if (commands[i].cmd) commands[i].func(argcp, argvp); else printf("%s: command not found\n", argvp[0]); g_strfreev(argvp); } static gboolean prompt_read(GIOChannel *chan, GIOCondition cond, gpointer user_data) { if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) { g_io_channel_unref(chan); return FALSE; } rl_callback_read_char(); return TRUE; } static char *completion_generator(const char *text, int state) { static int index = 0, len = 0; const char *cmd = NULL; if (state == 0) { index = 0; len = strlen(text); } while ((cmd = commands[index].cmd) != NULL) { index++; if (strncmp(cmd, text, len) == 0) return strdup(cmd); } return NULL; } static char **commands_completion(const char *text, int start, int end) { if (start == 0) return rl_completion_matches(text, &completion_generator); else return NULL; } int interactive(const gchar *src, const gchar *dst, const gchar *dst_type, int psm) { GIOChannel *pchan; gint events; opt_sec_level = g_strdup("low"); opt_src = g_strdup(src); opt_dst = g_strdup(dst); opt_dst_type = g_strdup(dst_type); opt_psm = psm; prompt = g_string_new(NULL); event_loop = g_main_loop_new(NULL, FALSE); pchan = g_io_channel_unix_new(fileno(stdin)); g_io_channel_set_close_on_unref(pchan, TRUE); events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL; g_io_add_watch(pchan, events, prompt_read, NULL); rl_attempted_completion_function = commands_completion; rl_callback_handler_install(get_prompt(), parse_line); g_main_loop_run(event_loop); rl_callback_handler_remove(); cmd_disconnect(0, NULL); g_io_channel_unref(pchan); g_main_loop_unref(event_loop); g_string_free(prompt, TRUE); g_free(opt_src); g_free(opt_dst); g_free(opt_sec_level); return 0; } bluez-4.101/attrib/gatt-service.c0000644000000000000000000002146611766125764013605 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "gattrib.h" #include "att.h" #include "gatt.h" #include "att-database.h" #include "attrib-server.h" #include "gatt-service.h" #include "log.h" struct gatt_info { bt_uuid_t uuid; uint8_t props; int authentication; int authorization; GSList *callbacks; unsigned int num_attrs; uint16_t *value_handle; uint16_t *ccc_handle; }; struct attrib_cb { attrib_event_t event; void *fn; void *user_data; }; static GSList *parse_opts(gatt_option opt1, va_list args) { gatt_option opt = opt1; struct gatt_info *info; struct attrib_cb *cb; GSList *l = NULL; info = g_new0(struct gatt_info, 1); l = g_slist_append(l, info); while (opt != GATT_OPT_INVALID) { switch (opt) { case GATT_OPT_CHR_UUID: bt_uuid16_create(&info->uuid, va_arg(args, int)); /* characteristic declaration and value */ info->num_attrs += 2; break; case GATT_OPT_CHR_PROPS: info->props = va_arg(args, int); if (info->props & (ATT_CHAR_PROPER_NOTIFY | ATT_CHAR_PROPER_INDICATE)) /* client characteristic configuration */ info->num_attrs += 1; /* TODO: "Extended Properties" property requires a * descriptor, but it is not supported yet. */ break; case GATT_OPT_CHR_VALUE_CB: cb = g_new0(struct attrib_cb, 1); cb->event = va_arg(args, attrib_event_t); cb->fn = va_arg(args, void *); cb->user_data = va_arg(args, void *); info->callbacks = g_slist_append(info->callbacks, cb); break; case GATT_OPT_CHR_VALUE_GET_HANDLE: info->value_handle = va_arg(args, void *); break; case GATT_OPT_CCC_GET_HANDLE: info->ccc_handle = va_arg(args, void *); break; case GATT_OPT_CHR_AUTHENTICATION: info->authentication = va_arg(args, gatt_option); break; case GATT_OPT_CHR_AUTHORIZATION: info->authorization = va_arg(args, gatt_option); break; default: error("Invalid option: %d", opt); } opt = va_arg(args, gatt_option); if (opt == GATT_OPT_CHR_UUID) { info = g_new0(struct gatt_info, 1); l = g_slist_append(l, info); } } return l; } static struct attribute *add_service_declaration(struct btd_adapter *adapter, uint16_t handle, uint16_t svc, bt_uuid_t *uuid) { bt_uuid_t bt_uuid; uint8_t atval[16]; int len; if (uuid->type == BT_UUID16) { att_put_u16(uuid->value.u16, &atval[0]); len = 2; } else if (uuid->type == BT_UUID128) { att_put_u128(uuid->value.u128, &atval[0]); len = 16; } else return NULL; bt_uuid16_create(&bt_uuid, svc); return attrib_db_add(adapter, handle, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, len); } static int att_read_reqs(int authorization, int authentication, uint8_t props) { if (authorization == GATT_CHR_VALUE_READ || authorization == GATT_CHR_VALUE_BOTH) return ATT_AUTHORIZATION; else if (authentication == GATT_CHR_VALUE_READ || authentication == GATT_CHR_VALUE_BOTH) return ATT_AUTHENTICATION; else if (!(props & ATT_CHAR_PROPER_READ)) return ATT_NOT_PERMITTED; return ATT_NONE; } static int att_write_reqs(int authorization, int authentication, uint8_t props) { if (authorization == GATT_CHR_VALUE_WRITE || authorization == GATT_CHR_VALUE_BOTH) return ATT_AUTHORIZATION; else if (authentication == GATT_CHR_VALUE_WRITE || authentication == GATT_CHR_VALUE_BOTH) return ATT_AUTHENTICATION; else if (!(props & (ATT_CHAR_PROPER_WRITE | ATT_CHAR_PROPER_WRITE_WITHOUT_RESP))) return ATT_NOT_PERMITTED; return ATT_NONE; } static gint find_callback(gconstpointer a, gconstpointer b) { const struct attrib_cb *cb = a; unsigned int event = GPOINTER_TO_UINT(b); return cb->event - event; } static gboolean add_characteristic(struct btd_adapter *adapter, uint16_t *handle, struct gatt_info *info) { int read_reqs, write_reqs; uint16_t h = *handle; struct attribute *a; bt_uuid_t bt_uuid; uint8_t atval[5]; GSList *l; if (!info->uuid.value.u16 || !info->props) { error("Characteristic UUID or properties are missing"); return FALSE; } read_reqs = att_read_reqs(info->authorization, info->authentication, info->props); write_reqs = att_write_reqs(info->authorization, info->authentication, info->props); /* TODO: static characteristic values are not supported, therefore a * callback must be always provided if a read/write property is set */ if (read_reqs != ATT_NOT_PERMITTED) { gpointer reqs = GUINT_TO_POINTER(ATTRIB_READ); if (!g_slist_find_custom(info->callbacks, reqs, find_callback)) { error("Callback for read required"); return FALSE; } } if (write_reqs != ATT_NOT_PERMITTED) { gpointer reqs = GUINT_TO_POINTER(ATTRIB_WRITE); if (!g_slist_find_custom(info->callbacks, reqs, find_callback)) { error("Callback for write required"); return FALSE; } } /* characteristic declaration */ bt_uuid16_create(&bt_uuid, GATT_CHARAC_UUID); atval[0] = info->props; att_put_u16(h + 1, &atval[1]); att_put_u16(info->uuid.value.u16, &atval[3]); if (attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, sizeof(atval)) == NULL) return FALSE; /* characteristic value */ a = attrib_db_add(adapter, h++, &info->uuid, read_reqs, write_reqs, NULL, 0); if (a == NULL) return FALSE; for (l = info->callbacks; l != NULL; l = l->next) { struct attrib_cb *cb = l->data; switch (cb->event) { case ATTRIB_READ: a->read_cb = cb->fn; break; case ATTRIB_WRITE: a->write_cb = cb->fn; break; } a->cb_user_data = cb->user_data; } if (info->value_handle != NULL) *info->value_handle = a->handle; /* client characteristic configuration descriptor */ if (info->props & (ATT_CHAR_PROPER_NOTIFY | ATT_CHAR_PROPER_INDICATE)) { uint8_t cfg_val[2]; bt_uuid16_create(&bt_uuid, GATT_CLIENT_CHARAC_CFG_UUID); cfg_val[0] = 0x00; cfg_val[1] = 0x00; a = attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_AUTHENTICATION, cfg_val, sizeof(cfg_val)); if (a == NULL) return FALSE; if (info->ccc_handle != NULL) *info->ccc_handle = a->handle; } *handle = h; return TRUE; } static void free_gatt_info(void *data) { struct gatt_info *info = data; g_slist_free_full(info->callbacks, g_free); g_free(info); } static void service_attr_del(struct btd_adapter *adapter, uint16_t start_handle, uint16_t end_handle) { uint16_t handle; for (handle = start_handle; handle <= end_handle; handle++) if (attrib_db_del(adapter, handle) < 0) error("Can't delete handle 0x%04x", handle); } gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid, bt_uuid_t *svc_uuid, gatt_option opt1, ...) { char uuidstr[MAX_LEN_UUID_STR]; uint16_t start_handle, h; unsigned int size; va_list args; GSList *chrs, *l; bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR); if (svc_uuid->type != BT_UUID16 && svc_uuid->type != BT_UUID128) { error("Invalid service uuid: %s", uuidstr); return FALSE; } va_start(args, opt1); chrs = parse_opts(opt1, args); va_end(args); /* calculate how many attributes are necessary for this service */ for (l = chrs, size = 1; l != NULL; l = l->next) { struct gatt_info *info = l->data; size += info->num_attrs; } start_handle = attrib_db_find_avail(adapter, svc_uuid, size); if (start_handle == 0) { error("Not enough free handles to register service"); goto fail; } DBG("New service: handle 0x%04x, UUID %s, %d attributes", start_handle, uuidstr, size); /* service declaration */ h = start_handle; if (add_service_declaration(adapter, h++, uuid, svc_uuid) == NULL) goto fail; for (l = chrs; l != NULL; l = l->next) { struct gatt_info *info = l->data; DBG("New characteristic: handle 0x%04x", h); if (!add_characteristic(adapter, &h, info)) { service_attr_del(adapter, start_handle, h - 1); goto fail; } } g_assert(size < USHRT_MAX); g_assert(h - start_handle == (uint16_t) size); g_slist_free_full(chrs, free_gatt_info); return TRUE; fail: g_slist_free_full(chrs, free_gatt_info); return FALSE; } bluez-4.101/attrib/utils.c0000644000000000000000000000556611766125764012353 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include #include "att.h" #include "gattrib.h" #include "gatt.h" #include "btio.h" #include "gatttool.h" GIOChannel *gatt_connect(const gchar *src, const gchar *dst, const gchar *dst_type, const gchar *sec_level, int psm, int mtu, BtIOConnect connect_cb) { GIOChannel *chan; bdaddr_t sba, dba; uint8_t dest_type; GError *err = NULL; BtIOSecLevel sec; /* Remote device */ if (dst == NULL) { g_printerr("Remote Bluetooth address required\n"); return NULL; } str2ba(dst, &dba); /* Local adapter */ if (src != NULL) { if (!strncmp(src, "hci", 3)) hci_devba(atoi(src + 3), &sba); else str2ba(src, &sba); } else bacpy(&sba, BDADDR_ANY); /* Not used for BR/EDR */ if (strcmp(dst_type, "random") == 0) dest_type = BDADDR_LE_RANDOM; else dest_type = BDADDR_LE_PUBLIC; if (strcmp(sec_level, "medium") == 0) sec = BT_IO_SEC_MEDIUM; else if (strcmp(sec_level, "high") == 0) sec = BT_IO_SEC_HIGH; else sec = BT_IO_SEC_LOW; if (psm == 0) chan = bt_io_connect(BT_IO_L2CAP, connect_cb, NULL, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &sba, BT_IO_OPT_DEST_BDADDR, &dba, BT_IO_OPT_DEST_TYPE, dest_type, BT_IO_OPT_CID, ATT_CID, BT_IO_OPT_SEC_LEVEL, sec, BT_IO_OPT_INVALID); else chan = bt_io_connect(BT_IO_L2CAP, connect_cb, NULL, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &sba, BT_IO_OPT_DEST_BDADDR, &dba, BT_IO_OPT_PSM, psm, BT_IO_OPT_IMTU, mtu, BT_IO_OPT_SEC_LEVEL, sec, BT_IO_OPT_INVALID); if (err) { g_printerr("%s\n", err->message); g_error_free(err); return NULL; } return chan; } size_t gatt_attr_data_from_string(const char *str, uint8_t **data) { char tmp[3]; size_t size, i; size = strlen(str) / 2; *data = g_try_malloc0(size); if (*data == NULL) return 0; tmp[2] = '\0'; for (i = 0; i < size; i++) { memcpy(tmp, str + (i * 2), 2); (*data)[i] = (uint8_t) strtol(tmp, NULL, 16); } return size; } bluez-4.101/attrib/gatt-service.h0000644000000000000000000000276711766125764013615 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ typedef enum { GATT_OPT_INVALID = 0, GATT_OPT_CHR_UUID, GATT_OPT_CHR_PROPS, GATT_OPT_CHR_VALUE_CB, GATT_OPT_CHR_AUTHENTICATION, GATT_OPT_CHR_AUTHORIZATION, /* Get attribute handle for characteristic value */ GATT_OPT_CHR_VALUE_GET_HANDLE, /* Get handle for ccc attribute */ GATT_OPT_CCC_GET_HANDLE, /* arguments for authentication/authorization */ GATT_CHR_VALUE_READ, GATT_CHR_VALUE_WRITE, GATT_CHR_VALUE_BOTH, } gatt_option; typedef enum { ATTRIB_READ, ATTRIB_WRITE, } attrib_event_t; gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid, bt_uuid_t *svc_uuid, gatt_option opt1, ...); bluez-4.101/attrib/gatt.c0000644000000000000000000003475611766125764012155 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "att.h" #include "gattrib.h" #include "gatt.h" struct discover_primary { GAttrib *attrib; bt_uuid_t uuid; GSList *primaries; gatt_cb_t cb; void *user_data; }; struct discover_char { GAttrib *attrib; bt_uuid_t *uuid; uint16_t end; GSList *characteristics; gatt_cb_t cb; void *user_data; }; static void discover_primary_free(struct discover_primary *dp) { g_slist_free(dp->primaries); g_attrib_unref(dp->attrib); g_free(dp); } static void discover_char_free(struct discover_char *dc) { g_slist_free_full(dc->characteristics, g_free); g_attrib_unref(dc->attrib); g_free(dc->uuid); g_free(dc); } static guint16 encode_discover_primary(uint16_t start, uint16_t end, bt_uuid_t *uuid, uint8_t *pdu, size_t len) { bt_uuid_t prim; guint16 plen; bt_uuid16_create(&prim, GATT_PRIM_SVC_UUID); if (uuid == NULL) { /* Discover all primary services */ plen = enc_read_by_grp_req(start, end, &prim, pdu, len); } else { uint16_t u16; uint128_t u128; const void *value; int vlen; /* Discover primary service by service UUID */ if (uuid->type == BT_UUID16) { u16 = htobs(uuid->value.u16); value = &u16; vlen = sizeof(u16); } else { htob128(&uuid->value.u128, &u128); value = &u128; vlen = sizeof(u128); } plen = enc_find_by_type_req(start, end, &prim, value, vlen, pdu, len); } return plen; } static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu, guint16 iplen, gpointer user_data) { struct discover_primary *dp = user_data; GSList *ranges, *last; struct att_range *range; uint8_t *buf; guint16 oplen; int err = 0, buflen; if (status) { err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status; goto done; } ranges = dec_find_by_type_resp(ipdu, iplen); if (ranges == NULL) goto done; dp->primaries = g_slist_concat(dp->primaries, ranges); last = g_slist_last(ranges); range = last->data; if (range->end == 0xffff) goto done; buf = g_attrib_get_buffer(dp->attrib, &buflen); oplen = encode_discover_primary(range->end + 1, 0xffff, &dp->uuid, buf, buflen); if (oplen == 0) goto done; g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_by_uuid_cb, dp, NULL); return; done: dp->cb(dp->primaries, err, dp->user_data); discover_primary_free(dp); } static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen, gpointer user_data) { struct discover_primary *dp = user_data; struct att_data_list *list; unsigned int i, err; uint16_t start, end; if (status) { err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status; goto done; } list = dec_read_by_grp_resp(ipdu, iplen); if (list == NULL) { err = ATT_ECODE_IO; goto done; } for (i = 0, end = 0; i < list->num; i++) { const uint8_t *data = list->data[i]; struct gatt_primary *primary; bt_uuid_t uuid; start = att_get_u16(&data[0]); end = att_get_u16(&data[2]); if (list->len == 6) { bt_uuid_t uuid16 = att_get_uuid16(&data[4]); bt_uuid_to_uuid128(&uuid16, &uuid); } else if (list->len == 20) { uuid = att_get_uuid128(&data[4]); } else { /* Skipping invalid data */ continue; } primary = g_try_new0(struct gatt_primary, 1); if (!primary) { err = ATT_ECODE_INSUFF_RESOURCES; goto done; } primary->range.start = start; primary->range.end = end; bt_uuid_to_string(&uuid, primary->uuid, sizeof(primary->uuid)); dp->primaries = g_slist_append(dp->primaries, primary); } att_data_list_free(list); err = 0; if (end != 0xffff) { int buflen; uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen); guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL, buf, buflen); g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_all_cb, dp, NULL); return; } done: dp->cb(dp->primaries, err, dp->user_data); discover_primary_free(dp); } guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func, gpointer user_data) { struct discover_primary *dp; int buflen; uint8_t *buf = g_attrib_get_buffer(attrib, &buflen); GAttribResultFunc cb; guint16 plen; plen = encode_discover_primary(0x0001, 0xffff, uuid, buf, buflen); if (plen == 0) return 0; dp = g_try_new0(struct discover_primary, 1); if (dp == NULL) return 0; dp->attrib = g_attrib_ref(attrib); dp->cb = func; dp->user_data = user_data; if (uuid) { dp->uuid = *uuid; cb = primary_by_uuid_cb; } else cb = primary_all_cb; return g_attrib_send(attrib, 0, buf[0], buf, plen, cb, dp, NULL); } static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen, gpointer user_data) { struct discover_char *dc = user_data; struct att_data_list *list; unsigned int i, err; int buflen; uint8_t *buf; guint16 oplen; bt_uuid_t uuid; uint16_t last = 0; if (status) { err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status; goto done; } list = dec_read_by_type_resp(ipdu, iplen); if (list == NULL) { err = ATT_ECODE_IO; goto done; } for (i = 0; i < list->num; i++) { uint8_t *value = list->data[i]; struct gatt_char *chars; bt_uuid_t uuid; last = att_get_u16(value); if (list->len == 7) { bt_uuid_t uuid16 = att_get_uuid16(&value[5]); bt_uuid_to_uuid128(&uuid16, &uuid); } else uuid = att_get_uuid128(&value[5]); chars = g_try_new0(struct gatt_char, 1); if (!chars) { err = ATT_ECODE_INSUFF_RESOURCES; goto done; } if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid)) break; chars->handle = last; chars->properties = value[2]; chars->value_handle = att_get_u16(&value[3]); bt_uuid_to_string(&uuid, chars->uuid, sizeof(chars->uuid)); dc->characteristics = g_slist_append(dc->characteristics, chars); } att_data_list_free(list); err = 0; if (last != 0 && (last + 1 < dc->end)) { buf = g_attrib_get_buffer(dc->attrib, &buflen); bt_uuid16_create(&uuid, GATT_CHARAC_UUID); oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, buf, buflen); if (oplen == 0) return; g_attrib_send(dc->attrib, 0, buf[0], buf, oplen, char_discovered_cb, dc, NULL); return; } done: dc->cb(dc->characteristics, err, dc->user_data); discover_char_free(dc); } guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end, bt_uuid_t *uuid, gatt_cb_t func, gpointer user_data) { int buflen; uint8_t *buf = g_attrib_get_buffer(attrib, &buflen); struct discover_char *dc; bt_uuid_t type_uuid; guint16 plen; bt_uuid16_create(&type_uuid, GATT_CHARAC_UUID); plen = enc_read_by_type_req(start, end, &type_uuid, buf, buflen); if (plen == 0) return 0; dc = g_try_new0(struct discover_char, 1); if (dc == NULL) return 0; dc->attrib = g_attrib_ref(attrib); dc->cb = func; dc->user_data = user_data; dc->end = end; dc->uuid = g_memdup(uuid, sizeof(bt_uuid_t)); return g_attrib_send(attrib, 0, buf[0], buf, plen, char_discovered_cb, dc, NULL); } guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end, bt_uuid_t *uuid, GAttribResultFunc func, gpointer user_data) { int buflen; uint8_t *buf = g_attrib_get_buffer(attrib, &buflen); guint16 plen; plen = enc_read_by_type_req(start, end, uuid, buf, buflen); if (plen == 0) return 0; return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ, buf, plen, func, user_data, NULL); } struct read_long_data { GAttrib *attrib; GAttribResultFunc func; gpointer user_data; guint8 *buffer; guint16 size; guint16 handle; guint id; gint ref; }; static void read_long_destroy(gpointer user_data) { struct read_long_data *long_read = user_data; if (g_atomic_int_dec_and_test(&long_read->ref) == FALSE) return; if (long_read->buffer != NULL) g_free(long_read->buffer); g_free(long_read); } static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen, gpointer user_data) { struct read_long_data *long_read = user_data; uint8_t *buf; int buflen; guint8 *tmp; guint16 plen; guint id; if (status != 0 || rlen == 1) { status = 0; goto done; } tmp = g_try_realloc(long_read->buffer, long_read->size + rlen - 1); if (tmp == NULL) { status = ATT_ECODE_INSUFF_RESOURCES; goto done; } memcpy(&tmp[long_read->size], &rpdu[1], rlen - 1); long_read->buffer = tmp; long_read->size += rlen - 1; buf = g_attrib_get_buffer(long_read->attrib, &buflen); if (rlen < buflen) goto done; plen = enc_read_blob_req(long_read->handle, long_read->size - 1, buf, buflen); id = g_attrib_send(long_read->attrib, long_read->id, ATT_OP_READ_BLOB_REQ, buf, plen, read_blob_helper, long_read, read_long_destroy); if (id != 0) { g_atomic_int_inc(&long_read->ref); return; } status = ATT_ECODE_IO; done: long_read->func(status, long_read->buffer, long_read->size, long_read->user_data); } static void read_char_helper(guint8 status, const guint8 *rpdu, guint16 rlen, gpointer user_data) { struct read_long_data *long_read = user_data; int buflen; uint8_t *buf = g_attrib_get_buffer(long_read->attrib, &buflen); guint16 plen; guint id; if (status != 0 || rlen < buflen) goto done; long_read->buffer = g_malloc(rlen); if (long_read->buffer == NULL) goto done; memcpy(long_read->buffer, rpdu, rlen); long_read->size = rlen; plen = enc_read_blob_req(long_read->handle, rlen - 1, buf, buflen); id = g_attrib_send(long_read->attrib, long_read->id, ATT_OP_READ_BLOB_REQ, buf, plen, read_blob_helper, long_read, read_long_destroy); if (id != 0) { g_atomic_int_inc(&long_read->ref); return; } status = ATT_ECODE_IO; done: long_read->func(status, rpdu, rlen, long_read->user_data); } guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset, GAttribResultFunc func, gpointer user_data) { uint8_t *buf; int buflen; guint16 plen; guint id; struct read_long_data *long_read; long_read = g_try_new0(struct read_long_data, 1); if (long_read == NULL) return 0; long_read->attrib = attrib; long_read->func = func; long_read->user_data = user_data; long_read->handle = handle; buf = g_attrib_get_buffer(attrib, &buflen); if (offset > 0) { plen = enc_read_blob_req(long_read->handle, offset, buf, buflen); id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, buf, plen, read_blob_helper, long_read, read_long_destroy); } else { plen = enc_read_req(handle, buf, buflen); id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, buf, plen, read_char_helper, long_read, read_long_destroy); } if (id == 0) g_free(long_read); else { g_atomic_int_inc(&long_read->ref); long_read->id = id; } return id; } guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen, GAttribResultFunc func, gpointer user_data) { uint8_t *buf; int buflen; guint16 plen; buf = g_attrib_get_buffer(attrib, &buflen); if (func) plen = enc_write_req(handle, value, vlen, buf, buflen); else plen = enc_write_cmd(handle, value, vlen, buf, buflen); return g_attrib_send(attrib, 0, buf[0], buf, plen, func, user_data, NULL); } guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func, gpointer user_data) { uint8_t *buf; int buflen; guint16 plen; buf = g_attrib_get_buffer(attrib, &buflen); plen = enc_mtu_req(mtu, buf, buflen); return g_attrib_send(attrib, 0, ATT_OP_MTU_REQ, buf, plen, func, user_data, NULL); } guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end, GAttribResultFunc func, gpointer user_data) { uint8_t *buf; int buflen; guint16 plen; buf = g_attrib_get_buffer(attrib, &buflen); plen = enc_find_info_req(start, end, buf, buflen); if (plen == 0) return 0; return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, buf, plen, func, user_data, NULL); } guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen, GDestroyNotify notify, gpointer user_data) { uint8_t *buf; int buflen; guint16 plen; buf = g_attrib_get_buffer(attrib, &buflen); plen = enc_write_cmd(handle, value, vlen, buf, buflen); return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, buf, plen, NULL, user_data, notify); } static sdp_data_t *proto_seq_find(sdp_list_t *proto_list) { sdp_list_t *list; uuid_t proto; sdp_uuid16_create(&proto, ATT_UUID); for (list = proto_list; list; list = list->next) { sdp_list_t *p; for (p = list->data; p; p = p->next) { sdp_data_t *seq = p->data; if (seq && seq->dtd == SDP_UUID16 && sdp_uuid16_cmp(&proto, &seq->val.uuid) == 0) return seq->next; } } return NULL; } static gboolean parse_proto_params(sdp_list_t *proto_list, uint16_t *psm, uint16_t *start, uint16_t *end) { sdp_data_t *seq1, *seq2; if (psm) *psm = sdp_get_proto_port(proto_list, L2CAP_UUID); /* Getting start and end handle */ seq1 = proto_seq_find(proto_list); if (!seq1 || seq1->dtd != SDP_UINT16) return FALSE; seq2 = seq1->next; if (!seq2 || seq2->dtd != SDP_UINT16) return FALSE; if (start) *start = seq1->val.uint16; if (end) *end = seq2->val.uint16; return TRUE; } gboolean gatt_parse_record(const sdp_record_t *rec, uuid_t *prim_uuid, uint16_t *psm, uint16_t *start, uint16_t *end) { sdp_list_t *list; uuid_t uuid; gboolean ret; if (sdp_get_service_classes(rec, &list) < 0) return FALSE; memcpy(&uuid, list->data, sizeof(uuid)); sdp_list_free(list, free); if (sdp_get_access_protos(rec, &list) < 0) return FALSE; ret = parse_proto_params(list, psm, start, end); sdp_list_foreach(list, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(list, NULL); /* FIXME: replace by bt_uuid_t after uuid_t/sdp code cleanup */ if (ret && prim_uuid) memcpy(prim_uuid, &uuid, sizeof(uuid_t)); return ret; } bluez-4.101/attrib/gattrib.h0000644000000000000000000000470311766125764012644 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __GATTRIB_H #define __GATTRIB_H #ifdef __cplusplus extern "C" { #endif #define GATTRIB_ALL_EVENTS 0xFF #define GATTRIB_ALL_REQS 0xFE struct _GAttrib; typedef struct _GAttrib GAttrib; typedef void (*GAttribResultFunc) (guint8 status, const guint8 *pdu, guint16 len, gpointer user_data); typedef void (*GAttribDisconnectFunc)(gpointer user_data); typedef void (*GAttribDebugFunc)(const char *str, gpointer user_data); typedef void (*GAttribNotifyFunc)(const guint8 *pdu, guint16 len, gpointer user_data); GAttrib *g_attrib_new(GIOChannel *io); GAttrib *g_attrib_ref(GAttrib *attrib); void g_attrib_unref(GAttrib *attrib); GIOChannel *g_attrib_get_channel(GAttrib *attrib); gboolean g_attrib_set_destroy_function(GAttrib *attrib, GDestroyNotify destroy, gpointer user_data); guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode, const guint8 *pdu, guint16 len, GAttribResultFunc func, gpointer user_data, GDestroyNotify notify); gboolean g_attrib_cancel(GAttrib *attrib, guint id); gboolean g_attrib_cancel_all(GAttrib *attrib); gboolean g_attrib_set_debug(GAttrib *attrib, GAttribDebugFunc func, gpointer user_data); guint g_attrib_register(GAttrib *attrib, guint8 opcode, GAttribNotifyFunc func, gpointer user_data, GDestroyNotify notify); gboolean g_attrib_is_encrypted(GAttrib *attrib); uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len); gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu); gboolean g_attrib_unregister(GAttrib *attrib, guint id); gboolean g_attrib_unregister_all(GAttrib *attrib); #ifdef __cplusplus } #endif #endif bluez-4.101/attrib/client.c0000644000000000000000000006511211766125764012462 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "adapter.h" #include "device.h" #include "log.h" #include "gdbus.h" #include "error.h" #include "dbus-common.h" #include "btio.h" #include "storage.h" #include "att.h" #include "gattrib.h" #include "attio.h" #include "gatt.h" #include "client.h" #define CHAR_INTERFACE "org.bluez.Characteristic" struct format { guint8 format; guint8 exponent; guint16 unit; guint8 namespace; guint16 desc; } __attribute__ ((packed)); struct query { DBusMessage *msg; GSList *list; }; struct gatt_service { struct btd_device *dev; struct gatt_primary *prim; DBusConnection *conn; GAttrib *attrib; guint attioid; int psm; char *path; GSList *chars; GSList *offline_chars; GSList *watchers; struct query *query; }; struct characteristic { struct gatt_service *gatt; char *path; uint16_t handle; uint16_t end; uint8_t perm; char type[MAX_LEN_UUID_STR + 1]; char *name; char *desc; struct format *format; uint8_t *value; size_t vlen; }; struct query_data { struct gatt_service *gatt; struct characteristic *chr; uint16_t handle; }; struct watcher { guint id; char *name; char *path; struct gatt_service *gatt; }; static GSList *gatt_services = NULL; static void characteristic_free(void *user_data) { struct characteristic *chr = user_data; g_free(chr->path); g_free(chr->desc); g_free(chr->format); g_free(chr->value); g_free(chr->name); g_free(chr); } static void watcher_free(void *user_data) { struct watcher *watcher = user_data; g_free(watcher->path); g_free(watcher->name); g_free(watcher); } static void gatt_service_free(struct gatt_service *gatt) { g_slist_free_full(gatt->watchers, watcher_free); g_slist_free_full(gatt->chars, characteristic_free); g_slist_free(gatt->offline_chars); g_free(gatt->path); btd_device_unref(gatt->dev); dbus_connection_unref(gatt->conn); g_free(gatt); } static void remove_attio(struct gatt_service *gatt) { if (gatt->offline_chars || gatt->watchers || gatt->query) return; if (gatt->attioid) { btd_device_remove_attio_callback(gatt->dev, gatt->attioid); gatt->attioid = 0; } if (gatt->attrib) { g_attrib_unref(gatt->attrib); gatt->attrib = NULL; } } static void gatt_get_address(struct gatt_service *gatt, bdaddr_t *sba, bdaddr_t *dba, uint8_t *bdaddr_type) { struct btd_device *device = gatt->dev; struct btd_adapter *adapter; adapter = device_get_adapter(device); adapter_get_address(adapter, sba); device_get_address(device, dba, bdaddr_type); } static int characteristic_handle_cmp(gconstpointer a, gconstpointer b) { const struct characteristic *chr = a; uint16_t handle = GPOINTER_TO_UINT(b); return chr->handle - handle; } static int watcher_cmp(gconstpointer a, gconstpointer b) { const struct watcher *watcher = a; const struct watcher *match = b; int ret; ret = g_strcmp0(watcher->name, match->name); if (ret != 0) return ret; return g_strcmp0(watcher->path, match->path); } static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr) { DBusMessageIter dict; const char *name = ""; char *uuid; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); uuid = g_strdup(chr->type); dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid); g_free(uuid); /* FIXME: Translate UUID to name. */ dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name); if (chr->desc) dict_append_entry(&dict, "Description", DBUS_TYPE_STRING, &chr->desc); if (chr->value) dict_append_array(&dict, "Value", DBUS_TYPE_BYTE, &chr->value, chr->vlen); /* FIXME: Missing Format, Value and Representation */ dbus_message_iter_close_container(iter, &dict); } static void watcher_exit(DBusConnection *conn, void *user_data) { struct watcher *watcher = user_data; struct gatt_service *gatt = watcher->gatt; DBG("%s watcher %s exited", gatt->path, watcher->name); gatt->watchers = g_slist_remove(gatt->watchers, watcher); g_dbus_remove_watch(gatt->conn, watcher->id); remove_attio(gatt); } static int characteristic_set_value(struct characteristic *chr, const uint8_t *value, size_t vlen) { chr->value = g_try_realloc(chr->value, vlen); if (chr->value == NULL) return -ENOMEM; memcpy(chr->value, value, vlen); chr->vlen = vlen; return 0; } static void update_watchers(gpointer data, gpointer user_data) { struct watcher *w = data; struct characteristic *chr = user_data; DBusConnection *conn = w->gatt->conn; DBusMessage *msg; msg = dbus_message_new_method_call(w->name, w->path, "org.bluez.Watcher", "ValueChanged"); if (msg == NULL) return; dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &chr->path, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &chr->value, chr->vlen, DBUS_TYPE_INVALID); dbus_message_set_no_reply(msg, TRUE); g_dbus_send_message(conn, msg); } static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data) { struct gatt_service *gatt = user_data; struct characteristic *chr; GSList *l; uint8_t opdu[ATT_MAX_MTU]; guint handle; uint16_t olen; if (len < 3) { DBG("Malformed notification/indication packet (opcode 0x%02x)", pdu[0]); return; } handle = att_get_u16(&pdu[1]); l = g_slist_find_custom(gatt->chars, GUINT_TO_POINTER(handle), characteristic_handle_cmp); if (!l) return; chr = l->data; if (chr == NULL) { DBG("Attribute handle 0x%02x not found", handle); return; } switch (pdu[0]) { case ATT_OP_HANDLE_IND: olen = enc_confirmation(opdu, sizeof(opdu)); g_attrib_send(gatt->attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL); case ATT_OP_HANDLE_NOTIFY: if (characteristic_set_value(chr, &pdu[3], len - 3) < 0) DBG("Can't change Characteristic 0x%02x", handle); g_slist_foreach(gatt->watchers, update_watchers, chr); break; } } static void offline_char_written(gpointer user_data) { struct characteristic *chr = user_data; struct gatt_service *gatt = chr->gatt; gatt->offline_chars = g_slist_remove(gatt->offline_chars, chr); remove_attio(gatt); } static void offline_char_write(gpointer data, gpointer user_data) { struct characteristic *chr = data; GAttrib *attrib = user_data; gatt_write_cmd(attrib, chr->handle, chr->value, chr->vlen, offline_char_written, chr); } static void char_discovered_cb(GSList *characteristics, guint8 status, gpointer user_data); static void attio_connected(GAttrib *attrib, gpointer user_data) { struct gatt_service *gatt = user_data; gatt->attrib = g_attrib_ref(attrib); g_attrib_register(gatt->attrib, ATT_OP_HANDLE_NOTIFY, events_handler, gatt, NULL); g_attrib_register(gatt->attrib, ATT_OP_HANDLE_IND, events_handler, gatt, NULL); g_slist_foreach(gatt->offline_chars, offline_char_write, attrib); if (gatt->query) { struct gatt_primary *prim = gatt->prim; struct query_data *qchr; qchr = g_slist_nth_data(gatt->query->list, 0); gatt_discover_char(gatt->attrib, prim->range.start, prim->range.end, NULL, char_discovered_cb, qchr); } } static void attio_disconnected(gpointer user_data) { struct gatt_service *gatt = user_data; if (gatt->query && gatt->query->msg) { DBusMessage *reply; reply = btd_error_failed(gatt->query->msg, "ATT IO channel was disconnected"); g_dbus_send_message(gatt->conn, reply); dbus_message_unref(gatt->query->msg); } if (gatt->query) { g_slist_free_full(gatt->query->list, g_free); gatt->query = NULL; } if (gatt->attrib) { g_attrib_unref(gatt->attrib); gatt->attrib = NULL; } } static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg, void *data) { const char *sender = dbus_message_get_sender(msg); struct gatt_service *gatt = data; struct watcher *watcher; char *path; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); watcher = g_new0(struct watcher, 1); watcher->name = g_strdup(sender); watcher->gatt = gatt; watcher->path = g_strdup(path); watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit, watcher, watcher_free); if (gatt->attioid == 0) gatt->attioid = btd_device_add_attio_callback(gatt->dev, attio_connected, attio_disconnected, gatt); gatt->watchers = g_slist_append(gatt->watchers, watcher); return dbus_message_new_method_return(msg); } static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg, void *data) { const char *sender = dbus_message_get_sender(msg); struct gatt_service *gatt = data; struct watcher *watcher, *match; GSList *l; char *path; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); match = g_new0(struct watcher, 1); match->name = g_strdup(sender); match->path = g_strdup(path); l = g_slist_find_custom(gatt->watchers, match, watcher_cmp); watcher_free(match); if (!l) return btd_error_not_authorized(msg); watcher = l->data; gatt->watchers = g_slist_remove(gatt->watchers, watcher); g_dbus_remove_watch(conn, watcher->id); remove_attio(gatt); return dbus_message_new_method_return(msg); } static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, struct characteristic *chr) { struct gatt_service *gatt = chr->gatt; DBusMessageIter sub; uint8_t *value; int len; if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY || dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE) return btd_error_invalid_args(msg); dbus_message_iter_recurse(iter, &sub); dbus_message_iter_get_fixed_array(&sub, &value, &len); characteristic_set_value(chr, value, len); if (gatt->attioid == 0) gatt->attioid = btd_device_add_attio_callback(gatt->dev, attio_connected, attio_disconnected, gatt); if (gatt->attrib) gatt_write_cmd(gatt->attrib, chr->handle, value, len, NULL, NULL); else gatt->offline_chars = g_slist_append(gatt->offline_chars, chr); return dbus_message_new_method_return(msg); } static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct characteristic *chr = data; DBusMessage *reply; DBusMessageIter iter; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); append_char_dict(&iter, chr); return reply; } static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, void *data) { struct characteristic *chr = data; DBusMessageIter iter; DBusMessageIter sub; const char *property; if (!dbus_message_iter_init(msg, &iter)) return btd_error_invalid_args(msg); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return btd_error_invalid_args(msg); dbus_message_iter_recurse(&iter, &sub); if (g_str_equal("Value", property)) return set_value(conn, msg, &sub, chr); return btd_error_invalid_args(msg); } static const GDBusMethodTable char_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), get_properties) }, { GDBUS_METHOD("SetProperty", GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL, set_property) }, { } }; static char *characteristic_list_to_string(GSList *chars) { GString *characteristics; GSList *l; characteristics = g_string_new(NULL); for (l = chars; l; l = l->next) { struct characteristic *chr = l->data; char chr_str[64]; memset(chr_str, 0, sizeof(chr_str)); snprintf(chr_str, sizeof(chr_str), "%04X#%02X#%04X#%s ", chr->handle, chr->perm, chr->end, chr->type); characteristics = g_string_append(characteristics, chr_str); } return g_string_free(characteristics, FALSE); } static void store_characteristics(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, uint16_t start, GSList *chars) { char *characteristics; characteristics = characteristic_list_to_string(chars); write_device_characteristics(sba, dba, bdaddr_type, start, characteristics); g_free(characteristics); } static void register_characteristic(gpointer data, gpointer user_data) { struct characteristic *chr = data; DBusConnection *conn = chr->gatt->conn; const char *gatt_path = user_data; chr->path = g_strdup_printf("%s/characteristic%04x", gatt_path, chr->handle); g_dbus_register_interface(conn, chr->path, CHAR_INTERFACE, char_methods, NULL, NULL, chr, NULL); DBG("Registered: %s", chr->path); } static GSList *string_to_characteristic_list(struct gatt_service *gatt, const char *str) { GSList *l = NULL; char **chars; int i; if (str == NULL) return NULL; chars = g_strsplit(str, " ", 0); if (chars == NULL) return NULL; for (i = 0; chars[i]; i++) { struct characteristic *chr; int ret; chr = g_new0(struct characteristic, 1); ret = sscanf(chars[i], "%04hX#%02hhX#%04hX#%s", &chr->handle, &chr->perm, &chr->end, chr->type); if (ret < 4) { g_free(chr); continue; } chr->gatt = gatt; l = g_slist_append(l, chr); } g_strfreev(chars); return l; } static GSList *load_characteristics(struct gatt_service *gatt, uint16_t start) { GSList *chrs_list; bdaddr_t sba, dba; uint8_t bdaddr_type; char *str; gatt_get_address(gatt, &sba, &dba, &bdaddr_type); str = read_device_characteristics(&sba, &dba, bdaddr_type, start); if (str == NULL) return NULL; chrs_list = string_to_characteristic_list(gatt, str); free(str); return chrs_list; } static void store_attribute(struct gatt_service *gatt, uint16_t handle, uint16_t type, uint8_t *value, gsize len) { struct btd_device *device = gatt->dev; bdaddr_t sba, dba; uint8_t bdaddr_type; bt_uuid_t uuid; char *str, *tmp; guint i; str = g_malloc0(MAX_LEN_UUID_STR + len * 2 + 1); bt_uuid16_create(&uuid, type); bt_uuid_to_string(&uuid, str, MAX_LEN_UUID_STR); str[MAX_LEN_UUID_STR - 1] = '#'; for (i = 0, tmp = str + MAX_LEN_UUID_STR; i < len; i++, tmp += 2) sprintf(tmp, "%02X", value[i]); gatt_get_address(gatt, &sba, &dba, NULL); bdaddr_type = device_get_addr_type(device); write_device_attribute(&sba, &dba, bdaddr_type, handle, str); g_free(str); } static void query_list_append(struct gatt_service *gatt, struct query_data *data) { struct query *query = gatt->query; query->list = g_slist_append(query->list, data); } static void query_list_remove(struct gatt_service *gatt, struct query_data *data) { struct query *query = gatt->query; query->list = g_slist_remove(query->list, data); if (query->list != NULL) return; g_free(query); gatt->query = NULL; remove_attio(gatt); } static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct characteristic *chr = current->chr; if (status == 0) { g_free(chr->desc); chr->desc = g_malloc(len); memcpy(chr->desc, pdu + 1, len - 1); chr->desc[len - 1] = '\0'; store_attribute(gatt, current->handle, GATT_CHARAC_USER_DESC_UUID, (void *) chr->desc, len); } else if (status == ATT_ECODE_INSUFF_ENC) { GIOChannel *io = g_attrib_get_channel(gatt->attrib); BtIOSecLevel level = BT_IO_SEC_HIGH; bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, &level, BT_IO_OPT_INVALID); if (level < BT_IO_SEC_HIGH) level++; if (bt_io_set(io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, level, BT_IO_OPT_INVALID)) { gatt_read_char(gatt->attrib, current->handle, 0, update_char_desc, current); return; } } query_list_remove(gatt, current); g_free(current); } static void update_char_format(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct characteristic *chr = current->chr; if (status != 0) goto done; if (len < 8) goto done; g_free(chr->format); chr->format = g_new0(struct format, 1); memcpy(chr->format, pdu + 1, 7); store_attribute(gatt, current->handle, GATT_CHARAC_FMT_UUID, (void *) chr->format, sizeof(*chr->format)); done: query_list_remove(gatt, current); g_free(current); } static void update_char_value(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct characteristic *chr = current->chr; if (status == 0) characteristic_set_value(chr, pdu + 1, len - 1); else if (status == ATT_ECODE_INSUFF_ENC) { GIOChannel *io = g_attrib_get_channel(gatt->attrib); if (bt_io_set(io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH, BT_IO_OPT_INVALID)) { gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, current); return; } } query_list_remove(gatt, current); g_free(current); } static int uuid_desc16_cmp(bt_uuid_t *uuid, guint16 desc) { bt_uuid_t u16; bt_uuid16_create(&u16, desc); return bt_uuid_cmp(uuid, &u16); } static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct att_data_list *list; guint8 format; int i; if (status != 0) goto done; DBG("Find Information Response received"); list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) goto done; for (i = 0; i < list->num; i++) { guint16 handle; bt_uuid_t uuid; uint8_t *info = list->data[i]; struct query_data *qfmt; handle = att_get_u16(info); if (format == 0x01) { uuid = att_get_uuid16(&info[2]); } else { /* Currently, only "user description" and "presentation * format" descriptors are used, and both have 16-bit * UUIDs. Therefore there is no need to support format * 0x02 yet. */ continue; } qfmt = g_new0(struct query_data, 1); qfmt->gatt = current->gatt; qfmt->chr = current->chr; qfmt->handle = handle; if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) { query_list_append(gatt, qfmt); gatt_read_char(gatt->attrib, handle, 0, update_char_desc, qfmt); } else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) { query_list_append(gatt, qfmt); gatt_read_char(gatt->attrib, handle, 0, update_char_format, qfmt); } else g_free(qfmt); } att_data_list_free(list); done: query_list_remove(gatt, current); g_free(current); } static void update_all_chars(gpointer data, gpointer user_data) { struct query_data *qdesc, *qvalue; struct characteristic *chr = data; struct gatt_service *gatt = user_data; qdesc = g_new0(struct query_data, 1); qdesc->gatt = gatt; qdesc->chr = chr; query_list_append(gatt, qdesc); gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb, qdesc); qvalue = g_new0(struct query_data, 1); qvalue->gatt = gatt; qvalue->chr = chr; query_list_append(gatt, qvalue); gatt_read_char(gatt->attrib, chr->handle, 0, update_char_value, qvalue); } static DBusMessage *create_discover_char_reply(DBusMessage *msg, GSList *chars) { DBusMessage *reply; DBusMessageIter iter, array_iter; GSList *l; reply = dbus_message_new_method_return(msg); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter); for (l = chars; l; l = l->next) { struct characteristic *chr = l->data; dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_OBJECT_PATH, &chr->path); } dbus_message_iter_close_container(&iter, &array_iter); return reply; } static void char_discovered_cb(GSList *characteristics, guint8 status, gpointer user_data) { DBusMessage *reply; struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct gatt_primary *prim = gatt->prim; uint16_t *previous_end = NULL; GSList *l; bdaddr_t sba, dba; uint8_t bdaddr_type; if (status != 0) { const char *str = att_ecode2str(status); DBG("Discover all characteristics failed: %s", str); reply = btd_error_failed(gatt->query->msg, str); goto fail; } for (l = characteristics; l; l = l->next) { struct gatt_char *current_chr = l->data; struct characteristic *chr; guint handle = current_chr->value_handle; GSList *lchr; lchr = g_slist_find_custom(gatt->chars, GUINT_TO_POINTER(handle), characteristic_handle_cmp); if (lchr) continue; chr = g_new0(struct characteristic, 1); chr->gatt = gatt; chr->perm = current_chr->properties; chr->handle = current_chr->value_handle; strncpy(chr->type, current_chr->uuid, sizeof(chr->type)); if (previous_end) *previous_end = current_chr->handle; previous_end = &chr->end; gatt->chars = g_slist_append(gatt->chars, chr); register_characteristic(chr, gatt->path); } if (previous_end) *previous_end = prim->range.end; gatt_get_address(gatt, &sba, &dba, &bdaddr_type); store_characteristics(&sba, &dba, bdaddr_type, prim->range.start, gatt->chars); g_slist_foreach(gatt->chars, update_all_chars, gatt); reply = create_discover_char_reply(gatt->query->msg, gatt->chars); fail: dbus_message_unref(gatt->query->msg); gatt->query->msg = NULL; g_dbus_send_message(gatt->conn, reply); query_list_remove(gatt, current); g_free(current); } static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg, void *data) { struct gatt_service *gatt = data; struct query *query; struct query_data *qchr; if (gatt->query) return btd_error_busy(msg); query = g_new0(struct query, 1); qchr = g_new0(struct query_data, 1); qchr->gatt = gatt; query->msg = dbus_message_ref(msg); if (gatt->attioid == 0) { gatt->attioid = btd_device_add_attio_callback(gatt->dev, attio_connected, attio_disconnected, gatt); } else if (gatt->attrib) { struct gatt_primary *prim = gatt->prim; gatt_discover_char(gatt->attrib, prim->range.start, prim->range.end, NULL, char_discovered_cb, qchr); } gatt->query = query; query_list_append(gatt, qchr); return NULL; } static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct gatt_service *gatt = data; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; GSList *l; char **chars; const char *uuid; int i; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); chars = g_new0(char *, g_slist_length(gatt->chars) + 1); for (i = 0, l = gatt->chars; l; l = l->next, i++) { struct characteristic *chr = l->data; chars[i] = chr->path; } dict_append_array(&dict, "Characteristics", DBUS_TYPE_OBJECT_PATH, &chars, i); uuid = gatt->prim->uuid; dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid); g_free(chars); dbus_message_iter_close_container(&iter, &dict); return reply; } static const GDBusMethodTable prim_methods[] = { { GDBUS_ASYNC_METHOD("DiscoverCharacteristics", NULL, GDBUS_ARGS({ "characteristics", "ao" }), discover_char) }, { GDBUS_METHOD("RegisterCharacteristicsWatcher", GDBUS_ARGS({ "agent", "o" }), NULL, register_watcher) }, { GDBUS_METHOD("UnregisterCharacteristicsWatcher", GDBUS_ARGS({ "agent", "o" }), NULL, unregister_watcher) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), prim_get_properties) }, { } }; static struct gatt_service *primary_register(DBusConnection *conn, struct btd_device *device, struct gatt_primary *prim, int psm) { struct gatt_service *gatt; const char *device_path; device_path = device_get_path(device); gatt = g_new0(struct gatt_service, 1); gatt->dev = btd_device_ref(device); gatt->prim = prim; gatt->psm = psm; gatt->conn = dbus_connection_ref(conn); gatt->path = g_strdup_printf("%s/service%04x", device_path, prim->range.start); g_dbus_register_interface(gatt->conn, gatt->path, CHAR_INTERFACE, prim_methods, NULL, NULL, gatt, NULL); gatt->chars = load_characteristics(gatt, prim->range.start); g_slist_foreach(gatt->chars, register_characteristic, gatt->path); return gatt; } GSList *attrib_client_register(DBusConnection *connection, struct btd_device *device, int psm, GAttrib *attrib, GSList *primaries) { GSList *l, *services; for (l = primaries, services = NULL; l; l = l->next) { struct gatt_primary *prim = l->data; struct gatt_service *gatt; gatt = primary_register(connection, device, prim, psm); DBG("Registered: %s", gatt->path); services = g_slist_append(services, g_strdup(gatt->path)); gatt_services = g_slist_append(gatt_services, gatt); } return services; } static void primary_unregister(struct gatt_service *gatt) { GSList *l; for (l = gatt->chars; l; l = l->next) { struct characteristic *chr = l->data; g_dbus_unregister_interface(gatt->conn, chr->path, CHAR_INTERFACE); } g_dbus_unregister_interface(gatt->conn, gatt->path, CHAR_INTERFACE); remove_attio(gatt); } static int path_cmp(gconstpointer data, gconstpointer user_data) { const char *path = data; const char *gatt_path = user_data; return g_strcmp0(path, gatt_path); } void attrib_client_unregister(GSList *services) { GSList *l, *left; for (l = gatt_services, left = NULL; l; l = l->next) { struct gatt_service *gatt = l->data; if (!g_slist_find_custom(services, gatt->path, path_cmp)) { left = g_slist_append(left, gatt); continue; } primary_unregister(gatt); gatt_service_free(gatt); } g_slist_free(gatt_services); gatt_services = left; } bluez-4.101/attrib/att.c0000644000000000000000000004446111766125764012000 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #include "att.h" const char *att_ecode2str(uint8_t status) { switch (status) { case ATT_ECODE_INVALID_HANDLE: return "Invalid handle"; case ATT_ECODE_READ_NOT_PERM: return "Attribute can't be read"; case ATT_ECODE_WRITE_NOT_PERM: return "Attribute can't be written"; case ATT_ECODE_INVALID_PDU: return "Attribute PDU was invalid"; case ATT_ECODE_AUTHENTICATION: return "Attribute requires authentication before read/write"; case ATT_ECODE_REQ_NOT_SUPP: return "Server doesn't support the request received"; case ATT_ECODE_INVALID_OFFSET: return "Offset past the end of the attribute"; case ATT_ECODE_AUTHORIZATION: return "Attribute requires authorization before read/write"; case ATT_ECODE_PREP_QUEUE_FULL: return "Too many prepare writes have been queued"; case ATT_ECODE_ATTR_NOT_FOUND: return "No attribute found within the given range"; case ATT_ECODE_ATTR_NOT_LONG: return "Attribute can't be read/written using Read Blob Req"; case ATT_ECODE_INSUFF_ENCR_KEY_SIZE: return "Encryption Key Size is insufficient"; case ATT_ECODE_INVAL_ATTR_VALUE_LEN: return "Attribute value length is invalid"; case ATT_ECODE_UNLIKELY: return "Request attribute has encountered an unlikely error"; case ATT_ECODE_INSUFF_ENC: return "Encryption required before read/write"; case ATT_ECODE_UNSUPP_GRP_TYPE: return "Attribute type is not a supported grouping attribute"; case ATT_ECODE_INSUFF_RESOURCES: return "Insufficient Resources to complete the request"; case ATT_ECODE_IO: return "Internal application error: I/O"; case ATT_ECODE_TIMEOUT: return "A timeout occured"; case ATT_ECODE_ABORTED: return "The operation was aborted"; default: return "Unexpected error code"; } } void att_data_list_free(struct att_data_list *list) { if (list == NULL) return; if (list->data) { int i; for (i = 0; i < list->num; i++) g_free(list->data[i]); } g_free(list->data); g_free(list); } struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len) { struct att_data_list *list; int i; list = g_new0(struct att_data_list, 1); list->len = len; list->num = num; list->data = g_malloc0(sizeof(uint8_t *) * num); for (i = 0; i < num; i++) list->data[i] = g_malloc0(sizeof(uint8_t) * len); return list; } uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); uint16_t length; if (!uuid) return 0; if (uuid->type == BT_UUID16) length = 2; else if (uuid->type == BT_UUID128) length = 16; else return 0; if (len < min_len + length) return 0; pdu[0] = ATT_OP_READ_BY_GROUP_REQ; att_put_u16(start, &pdu[1]); att_put_u16(end, &pdu[3]); att_put_uuid(*uuid, &pdu[5]); return min_len + length; } uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start, uint16_t *end, bt_uuid_t *uuid) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); if (pdu == NULL) return 0; if (start == NULL || end == NULL || uuid == NULL) return 0; if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ) return 0; if (len < min_len + 2) return 0; *start = att_get_u16(&pdu[1]); *end = att_get_u16(&pdu[3]); if (len == min_len + 2) *uuid = att_get_uuid16(&pdu[5]); else *uuid = att_get_uuid128(&pdu[5]); return len; } uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, int len) { int i; uint16_t w; uint8_t *ptr; if (list == NULL) return 0; if (len < list->len + 2) return 0; pdu[0] = ATT_OP_READ_BY_GROUP_RESP; pdu[1] = list->len; ptr = &pdu[2]; for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) { memcpy(ptr, list->data[i], list->len); ptr += list->len; w += list->len; } return w; } struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len) { struct att_data_list *list; const uint8_t *ptr; uint16_t elen, num; int i; if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP) return NULL; elen = pdu[1]; num = (len - 2) / elen; list = att_data_list_alloc(num, elen); ptr = &pdu[2]; for (i = 0; i < num; i++) { memcpy(list->data[i], ptr, list->len); ptr += list->len; } return list; } uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, const uint8_t *value, int vlen, uint8_t *pdu, int len) { uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end) + sizeof(uint16_t); if (pdu == NULL) return 0; if (!uuid) return 0; if (uuid->type != BT_UUID16) return 0; if (len < min_len) return 0; if (vlen > len - min_len) vlen = len - min_len; pdu[0] = ATT_OP_FIND_BY_TYPE_REQ; att_put_u16(start, &pdu[1]); att_put_u16(end, &pdu[3]); att_put_uuid16(*uuid, &pdu[5]); if (vlen > 0) { memcpy(&pdu[7], value, vlen); return min_len + vlen; } return min_len; } uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start, uint16_t *end, bt_uuid_t *uuid, uint8_t *value, int *vlen) { int valuelen; uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end) + sizeof(uint16_t); if (pdu == NULL) return 0; if (len < min_len) return 0; if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ) return 0; /* First requested handle number */ if (start) *start = att_get_u16(&pdu[1]); /* Last requested handle number */ if (end) *end = att_get_u16(&pdu[3]); /* Always UUID16 */ if (uuid) *uuid = att_get_uuid16(&pdu[5]); valuelen = len - min_len; /* Attribute value to find */ if (valuelen > 0 && value) memcpy(value, pdu + min_len, valuelen); if (vlen) *vlen = valuelen; return len; } uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, int len) { GSList *l; uint16_t offset; if (pdu == NULL || len < 5) return 0; pdu[0] = ATT_OP_FIND_BY_TYPE_RESP; for (l = matches, offset = 1; l && len >= (offset + 4); l = l->next, offset += 4) { struct att_range *range = l->data; att_put_u16(range->start, &pdu[offset]); att_put_u16(range->end, &pdu[offset + 2]); } return offset; } GSList *dec_find_by_type_resp(const uint8_t *pdu, int len) { struct att_range *range; GSList *matches; int offset; if (pdu == NULL || len < 5) return NULL; if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP) return NULL; for (offset = 1, matches = NULL; len >= (offset + 4); offset += 4) { range = g_new0(struct att_range, 1); range->start = att_get_u16(&pdu[offset]); range->end = att_get_u16(&pdu[offset + 2]); matches = g_slist_append(matches, range); } return matches; } uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); uint16_t length; if (!uuid) return 0; if (uuid->type == BT_UUID16) length = 2; else if (uuid->type == BT_UUID128) length = 16; else return 0; if (len < min_len + length) return 0; pdu[0] = ATT_OP_READ_BY_TYPE_REQ; att_put_u16(start, &pdu[1]); att_put_u16(end, &pdu[3]); att_put_uuid(*uuid, &pdu[5]); return min_len + length; } uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start, uint16_t *end, bt_uuid_t *uuid) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); if (pdu == NULL) return 0; if (start == NULL || end == NULL || uuid == NULL) return 0; if (len < min_len + 2) return 0; if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ) return 0; *start = att_get_u16(&pdu[1]); *end = att_get_u16(&pdu[3]); if (len == min_len + 2) *uuid = att_get_uuid16(&pdu[5]); else *uuid = att_get_uuid128(&pdu[5]); return len; } uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, int len) { uint8_t *ptr; int i, w, l; if (list == NULL) return 0; if (pdu == NULL) return 0; l = MIN(len - 2, list->len); pdu[0] = ATT_OP_READ_BY_TYPE_RESP; pdu[1] = l; ptr = &pdu[2]; for (i = 0, w = 2; i < list->num && w + l <= len; i++) { memcpy(ptr, list->data[i], l); ptr += l; w += l; } return w; } struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len) { struct att_data_list *list; const uint8_t *ptr; uint16_t elen, num; int i; if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP) return NULL; elen = pdu[1]; num = (len - 2) / elen; list = att_data_list_alloc(num, elen); ptr = &pdu[2]; for (i = 0; i < num; i++) { memcpy(list->data[i], ptr, list->len); ptr += list->len; } return list; } uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); if (pdu == NULL) return 0; if (len < min_len) return 0; if (vlen > len - min_len) vlen = len - min_len; pdu[0] = ATT_OP_WRITE_CMD; att_put_u16(handle, &pdu[1]); if (vlen > 0) { memcpy(&pdu[3], value, vlen); return min_len + vlen; } return min_len; } uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle, uint8_t *value, int *vlen) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); if (pdu == NULL) return 0; if (value == NULL || vlen == NULL || handle == NULL) return 0; if (len < min_len) return 0; if (pdu[0] != ATT_OP_WRITE_CMD) return 0; *handle = att_get_u16(&pdu[1]); memcpy(value, pdu + min_len, len - min_len); *vlen = len - min_len; return len; } uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); if (pdu == NULL) return 0; if (len < min_len) return 0; if (vlen > len - min_len) vlen = len - min_len; pdu[0] = ATT_OP_WRITE_REQ; att_put_u16(handle, &pdu[1]); if (vlen > 0) { memcpy(&pdu[3], value, vlen); return min_len + vlen; } return min_len; } uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle, uint8_t *value, int *vlen) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); if (pdu == NULL) return 0; if (value == NULL || vlen == NULL || handle == NULL) return 0; if (len < min_len) return 0; if (pdu[0] != ATT_OP_WRITE_REQ) return 0; *handle = att_get_u16(&pdu[1]); *vlen = len - min_len; if (*vlen > 0) memcpy(value, pdu + min_len, *vlen); return len; } uint16_t enc_write_resp(uint8_t *pdu, int len) { if (pdu == NULL) return 0; pdu[0] = ATT_OP_WRITE_RESP; return sizeof(pdu[0]); } uint16_t dec_write_resp(const uint8_t *pdu, int len) { if (pdu == NULL) return 0; if (pdu[0] != ATT_OP_WRITE_RESP) return 0; return len; } uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle); if (pdu == NULL) return 0; if (len < min_len) return 0; pdu[0] = ATT_OP_READ_REQ; att_put_u16(handle, &pdu[1]); return min_len; } uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) + sizeof(offset); if (pdu == NULL) return 0; if (len < min_len) return 0; pdu[0] = ATT_OP_READ_BLOB_REQ; att_put_u16(handle, &pdu[1]); att_put_u16(offset, &pdu[3]); return min_len; } uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle); if (pdu == NULL) return 0; if (handle == NULL) return 0; if (len < min_len) return 0; if (pdu[0] != ATT_OP_READ_REQ) return 0; *handle = att_get_u16(&pdu[1]); return min_len; } uint16_t dec_read_blob_req(const uint8_t *pdu, int len, uint16_t *handle, uint16_t *offset) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) + sizeof(*offset); if (pdu == NULL) return 0; if (handle == NULL) return 0; if (offset == NULL) return 0; if (len < min_len) return 0; if (pdu[0] != ATT_OP_READ_BLOB_REQ) return 0; *handle = att_get_u16(&pdu[1]); *offset = att_get_u16(&pdu[3]); return min_len; } uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len) { if (pdu == NULL) return 0; /* If the attribute value length is longer than the allowed PDU size, * send only the octets that fit on the PDU. The remaining octets can * be requested using the Read Blob Request. */ if (vlen > len - 1) vlen = len - 1; pdu[0] = ATT_OP_READ_RESP; memcpy(pdu + 1, value, vlen); return vlen + 1; } uint16_t enc_read_blob_resp(uint8_t *value, int vlen, uint16_t offset, uint8_t *pdu, int len) { if (pdu == NULL) return 0; vlen -= offset; if (vlen > len - 1) vlen = len - 1; pdu[0] = ATT_OP_READ_BLOB_RESP; memcpy(pdu + 1, &value[offset], vlen); return vlen + 1; } uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen) { if (pdu == NULL) return 0; if (value == NULL || vlen == NULL) return 0; if (pdu[0] != ATT_OP_READ_RESP) return 0; memcpy(value, pdu + 1, len - 1); *vlen = len - 1; return len; } uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) + sizeof(handle) + sizeof(status); uint16_t u16; if (len < min_len) return 0; u16 = htobs(handle); pdu[0] = ATT_OP_ERROR; pdu[1] = opcode; memcpy(&pdu[2], &u16, sizeof(u16)); pdu[4] = status; return min_len; } uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end); if (pdu == NULL) return 0; if (len < min_len) return 0; pdu[0] = ATT_OP_FIND_INFO_REQ; att_put_u16(start, &pdu[1]); att_put_u16(end, &pdu[3]); return min_len; } uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start, uint16_t *end) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end); if (pdu == NULL) return 0; if (len < min_len) return 0; if (start == NULL || end == NULL) return 0; if (pdu[0] != ATT_OP_FIND_INFO_REQ) return 0; *start = att_get_u16(&pdu[1]); *end = att_get_u16(&pdu[3]); return min_len; } uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list, uint8_t *pdu, int len) { uint8_t *ptr; int i, w; if (pdu == NULL) return 0; if (list == NULL) return 0; if (len < list->len + 2) return 0; pdu[0] = ATT_OP_FIND_INFO_RESP; pdu[1] = format; ptr = (void *) &pdu[2]; for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) { memcpy(ptr, list->data[i], list->len); ptr += list->len; w += list->len; } return w; } struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len, uint8_t *format) { struct att_data_list *list; uint8_t *ptr; uint16_t elen, num; int i; if (pdu == NULL) return 0; if (format == NULL) return 0; if (pdu[0] != ATT_OP_FIND_INFO_RESP) return 0; *format = pdu[1]; elen = sizeof(pdu[0]) + sizeof(*format); if (*format == 0x01) elen += 2; else if (*format == 0x02) elen += 16; num = (len - 2) / elen; ptr = (void *) &pdu[2]; list = att_data_list_alloc(num, elen); for (i = 0; i < num; i++) { memcpy(list->data[i], ptr, list->len); ptr += list->len; } return list; } uint16_t enc_notification(uint16_t handle, uint8_t *value, int vlen, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); if (pdu == NULL) return 0; if (len < (vlen + min_len)) return 0; pdu[0] = ATT_OP_HANDLE_NOTIFY; att_put_u16(handle, &pdu[1]); memcpy(&pdu[3], value, vlen); return vlen + min_len; } uint16_t enc_indication(uint16_t handle, uint8_t *value, int vlen, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); if (pdu == NULL) return 0; if (len < (vlen + min_len)) return 0; pdu[0] = ATT_OP_HANDLE_IND; att_put_u16(handle, &pdu[1]); memcpy(&pdu[3], value, vlen); return vlen + min_len; } uint16_t dec_indication(const uint8_t *pdu, int len, uint16_t *handle, uint8_t *value, int vlen) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t); uint16_t dlen; if (pdu == NULL) return 0; if (pdu[0] != ATT_OP_HANDLE_IND) return 0; if (len < min_len) return 0; dlen = MIN(len - min_len, vlen); if (handle) *handle = att_get_u16(&pdu[1]); memcpy(value, &pdu[3], dlen); return dlen; } uint16_t enc_confirmation(uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]); if (pdu == NULL) return 0; if (len < min_len) return 0; pdu[0] = ATT_OP_HANDLE_CNF; return min_len; } uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu); if (pdu == NULL) return 0; if (len < min_len) return 0; pdu[0] = ATT_OP_MTU_REQ; att_put_u16(mtu, &pdu[1]); return min_len; } uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu); if (pdu == NULL) return 0; if (mtu == NULL) return 0; if (len < min_len) return 0; if (pdu[0] != ATT_OP_MTU_REQ) return 0; *mtu = att_get_u16(&pdu[1]); return min_len; } uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu); if (pdu == NULL) return 0; if (len < min_len) return 0; pdu[0] = ATT_OP_MTU_RESP; att_put_u16(mtu, &pdu[1]); return min_len; } uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu) { const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu); if (pdu == NULL) return 0; if (mtu == NULL) return 0; if (len < min_len) return 0; if (pdu[0] != ATT_OP_MTU_RESP) return 0; *mtu = att_get_u16(&pdu[1]); return min_len; } bluez-4.101/attrib/client.h0000644000000000000000000000210211766125764012455 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ GSList *attrib_client_register(DBusConnection *connection, struct btd_device *device, int psm, GAttrib *attrib, GSList *primaries); void attrib_client_unregister(GSList *services); bluez-4.101/attrib/att.h0000644000000000000000000002054411766125764012001 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* Attribute Protocol Opcodes */ #define ATT_OP_ERROR 0x01 #define ATT_OP_MTU_REQ 0x02 #define ATT_OP_MTU_RESP 0x03 #define ATT_OP_FIND_INFO_REQ 0x04 #define ATT_OP_FIND_INFO_RESP 0x05 #define ATT_OP_FIND_BY_TYPE_REQ 0x06 #define ATT_OP_FIND_BY_TYPE_RESP 0x07 #define ATT_OP_READ_BY_TYPE_REQ 0x08 #define ATT_OP_READ_BY_TYPE_RESP 0x09 #define ATT_OP_READ_REQ 0x0A #define ATT_OP_READ_RESP 0x0B #define ATT_OP_READ_BLOB_REQ 0x0C #define ATT_OP_READ_BLOB_RESP 0x0D #define ATT_OP_READ_MULTI_REQ 0x0E #define ATT_OP_READ_MULTI_RESP 0x0F #define ATT_OP_READ_BY_GROUP_REQ 0x10 #define ATT_OP_READ_BY_GROUP_RESP 0x11 #define ATT_OP_WRITE_REQ 0x12 #define ATT_OP_WRITE_RESP 0x13 #define ATT_OP_WRITE_CMD 0x52 #define ATT_OP_PREP_WRITE_REQ 0x16 #define ATT_OP_PREP_WRITE_RESP 0x17 #define ATT_OP_EXEC_WRITE_REQ 0x18 #define ATT_OP_EXEC_WRITE_RESP 0x19 #define ATT_OP_HANDLE_NOTIFY 0x1B #define ATT_OP_HANDLE_IND 0x1D #define ATT_OP_HANDLE_CNF 0x1E #define ATT_OP_SIGNED_WRITE_CMD 0xD2 /* Error codes for Error response PDU */ #define ATT_ECODE_INVALID_HANDLE 0x01 #define ATT_ECODE_READ_NOT_PERM 0x02 #define ATT_ECODE_WRITE_NOT_PERM 0x03 #define ATT_ECODE_INVALID_PDU 0x04 #define ATT_ECODE_AUTHENTICATION 0x05 #define ATT_ECODE_REQ_NOT_SUPP 0x06 #define ATT_ECODE_INVALID_OFFSET 0x07 #define ATT_ECODE_AUTHORIZATION 0x08 #define ATT_ECODE_PREP_QUEUE_FULL 0x09 #define ATT_ECODE_ATTR_NOT_FOUND 0x0A #define ATT_ECODE_ATTR_NOT_LONG 0x0B #define ATT_ECODE_INSUFF_ENCR_KEY_SIZE 0x0C #define ATT_ECODE_INVAL_ATTR_VALUE_LEN 0x0D #define ATT_ECODE_UNLIKELY 0x0E #define ATT_ECODE_INSUFF_ENC 0x0F #define ATT_ECODE_UNSUPP_GRP_TYPE 0x10 #define ATT_ECODE_INSUFF_RESOURCES 0x11 /* Application error */ #define ATT_ECODE_IO 0x80 #define ATT_ECODE_TIMEOUT 0x81 #define ATT_ECODE_ABORTED 0x82 /* Characteristic Property bit field */ #define ATT_CHAR_PROPER_BROADCAST 0x01 #define ATT_CHAR_PROPER_READ 0x02 #define ATT_CHAR_PROPER_WRITE_WITHOUT_RESP 0x04 #define ATT_CHAR_PROPER_WRITE 0x08 #define ATT_CHAR_PROPER_NOTIFY 0x10 #define ATT_CHAR_PROPER_INDICATE 0x20 #define ATT_CHAR_PROPER_AUTH 0x40 #define ATT_CHAR_PROPER_EXT_PROPER 0x80 #define ATT_MAX_MTU 256 #define ATT_DEFAULT_L2CAP_MTU 48 #define ATT_DEFAULT_LE_MTU 23 #define ATT_CID 4 #define ATT_PSM 31 struct att_data_list { uint16_t num; uint16_t len; uint8_t **data; }; struct att_range { uint16_t start; uint16_t end; }; /* These functions do byte conversion */ static inline uint8_t att_get_u8(const void *ptr) { const uint8_t *u8_ptr = ptr; return bt_get_unaligned(u8_ptr); } static inline uint16_t att_get_u16(const void *ptr) { const uint16_t *u16_ptr = ptr; return btohs(bt_get_unaligned(u16_ptr)); } static inline uint32_t att_get_u32(const void *ptr) { const uint32_t *u32_ptr = ptr; return btohl(bt_get_unaligned(u32_ptr)); } static inline uint128_t att_get_u128(const void *ptr) { const uint128_t *u128_ptr = ptr; uint128_t dst; btoh128(u128_ptr, &dst); return dst; } static inline void att_put_u8(uint8_t src, void *dst) { bt_put_unaligned(src, (uint8_t *) dst); } static inline void att_put_u16(uint16_t src, void *dst) { bt_put_unaligned(htobs(src), (uint16_t *) dst); } static inline void att_put_u32(uint32_t src, void *dst) { bt_put_unaligned(htobl(src), (uint32_t *) dst); } static inline void att_put_u128(uint128_t src, void *dst) { uint128_t *d128 = dst; htob128(&src, d128); } static inline void att_put_uuid16(bt_uuid_t src, void *dst) { att_put_u16(src.value.u16, dst); } static inline void att_put_uuid128(bt_uuid_t src, void *dst) { att_put_u128(src.value.u128, dst); } static inline void att_put_uuid(bt_uuid_t src, void *dst) { if (src.type == BT_UUID16) att_put_uuid16(src, dst); else att_put_uuid128(src, dst); } static inline bt_uuid_t att_get_uuid16(const void *ptr) { bt_uuid_t uuid; bt_uuid16_create(&uuid, att_get_u16(ptr)); return uuid; } static inline bt_uuid_t att_get_uuid128(const void *ptr) { bt_uuid_t uuid; uint128_t value; value = att_get_u128(ptr); bt_uuid128_create(&uuid, value); return uuid; } struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len); void att_data_list_free(struct att_data_list *list); const char *att_ecode2str(uint8_t status); uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, uint8_t *pdu, int len); uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start, uint16_t *end, bt_uuid_t *uuid); uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, int len); uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, const uint8_t *value, int vlen, uint8_t *pdu, int len); uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start, uint16_t *end, bt_uuid_t *uuid, uint8_t *value, int *vlen); uint16_t enc_find_by_type_resp(GSList *ranges, uint8_t *pdu, int len); GSList *dec_find_by_type_resp(const uint8_t *pdu, int len); struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len); uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid, uint8_t *pdu, int len); uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start, uint16_t *end, bt_uuid_t *uuid); uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, int len); uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen, uint8_t *pdu, int len); uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle, uint8_t *value, int *vlen); struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len); uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen, uint8_t *pdu, int len); uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle, uint8_t *value, int *vlen); uint16_t enc_write_resp(uint8_t *pdu, int len); uint16_t dec_write_resp(const uint8_t *pdu, int len); uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len); uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu, int len); uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle); uint16_t dec_read_blob_req(const uint8_t *pdu, int len, uint16_t *handle, uint16_t *offset); uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len); uint16_t enc_read_blob_resp(uint8_t *value, int vlen, uint16_t offset, uint8_t *pdu, int len); uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen); uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status, uint8_t *pdu, int len); uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len); uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start, uint16_t *end); uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list, uint8_t *pdu, int len); struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len, uint8_t *format); uint16_t enc_notification(uint16_t handle, uint8_t *value, int vlen, uint8_t *pdu, int len); uint16_t enc_indication(uint16_t handle, uint8_t *value, int vlen, uint8_t *pdu, int len); uint16_t dec_indication(const uint8_t *pdu, int len, uint16_t *handle, uint8_t *value, int vlen); uint16_t enc_confirmation(uint8_t *pdu, int len); uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len); uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu); uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len); uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu); bluez-4.101/missing0000755000000000000000000002415211771117505011137 00000000000000#! /bin/sh # Common stub for a few missing GNU programs while installing. scriptversion=2012-01-06.13; # UTC # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006, # 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. # Originally by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program 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 General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try \`$0 --help' for more information" exit 1 fi run=: sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' sed_minuso='s/.* -o \([^ ]*\).*/\1/p' # In the cases where this matters, `missing' is being run in the # srcdir already. if test -f configure.ac; then configure_ac=configure.ac else configure_ac=configure.in fi msg="missing on your system" case $1 in --run) # Try to run requested program, and just exit if it succeeds. run= shift "$@" && exit 0 # Exit code 63 means version mismatch. This often happens # when the user try to use an ancient version of a tool on # a file that requires a minimum version. In this case we # we should proceed has if the program had been absent, or # if --run hadn't been passed. if test $? = 63; then run=: msg="probably too old" fi ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an error status if there is no known handling for PROGRAM. Options: -h, --help display this help and exit -v, --version output version information and exit --run try to run the given command, and emulate it if it fails Supported PROGRAM values: aclocal touch file \`aclocal.m4' autoconf touch file \`configure' autoheader touch file \`config.h.in' autom4te touch the output file, or create a stub one automake touch all \`Makefile.in' files bison create \`y.tab.[ch]', if possible, from existing .[ch] flex create \`lex.yy.c', if possible, from existing .c help2man touch the output file lex create \`lex.yy.c', if possible, from existing .c makeinfo touch the output file yacc create \`y.tab.[ch]', if possible, from existing .[ch] Version suffixes to PROGRAM as well as the prefixes \`gnu-', \`gnu', and \`g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: Unknown \`$1' option" echo 1>&2 "Try \`$0 --help' for more information" exit 1 ;; esac # normalize program name to check for. program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` # Now exit if we have it, but it failed. Also exit now if we # don't have it and --version was passed (most likely to detect # the program). This is about non-GNU programs, so use $1 not # $program. case $1 in lex*|yacc*) # Not GNU programs, they don't have --version. ;; *) if test -z "$run" && ($1 --version) > /dev/null 2>&1; then # We have it, but it failed. exit 1 elif test "x$2" = "x--version" || test "x$2" = "x--help"; then # Could not run --version or --help. This is probably someone # running `$TOOL --version' or `$TOOL --help' to check whether # $TOOL exists and not knowing $TOOL uses missing. exit 1 fi ;; esac # If it does not exist, or fails to run (possibly an outdated version), # try to emulate it. case $program in aclocal*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." touch aclocal.m4 ;; autoconf*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." touch configure ;; autoheader*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`acconfig.h' or \`${configure_ac}'. You might want to install the \`Autoconf' and \`GNU m4' packages. Grab them from any GNU archive site." files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` test -z "$files" && files="config.h" touch_files= for f in $files; do case $f in *:*) touch_files="$touch_files "`echo "$f" | sed -e 's/^[^:]*://' -e 's/:.*//'`;; *) touch_files="$touch_files $f.in";; esac done touch $touch_files ;; automake*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. You might want to install the \`Automake' and \`Perl' packages. Grab them from any GNU archive site." find . -type f -name Makefile.am -print | sed 's/\.am$/.in/' | while read f; do touch "$f"; done ;; autom4te*) echo 1>&2 "\ WARNING: \`$1' is needed, but is $msg. You might have modified some files without having the proper tools for further handling them. You can get \`$1' as part of \`Autoconf' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo "#! /bin/sh" echo "# Created by GNU Automake missing as a replacement of" echo "# $ $@" echo "exit 0" chmod +x $file exit 1 fi ;; bison*|yacc*) echo 1>&2 "\ WARNING: \`$1' $msg. You should only need it if you modified a \`.y' file. You may need the \`Bison' package in order for those modifications to take effect. You can get \`Bison' from any GNU archive site." rm -f y.tab.c y.tab.h if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.y) SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.c fi SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` if test -f "$SRCFILE"; then cp "$SRCFILE" y.tab.h fi ;; esac fi if test ! -f y.tab.h; then echo >y.tab.h fi if test ! -f y.tab.c; then echo 'main() { return 0; }' >y.tab.c fi ;; lex*|flex*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.l' file. You may need the \`Flex' package in order for those modifications to take effect. You can get \`Flex' from any GNU archive site." rm -f lex.yy.c if test $# -ne 1; then eval LASTARG=\${$#} case $LASTARG in *.l) SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` if test -f "$SRCFILE"; then cp "$SRCFILE" lex.yy.c fi ;; esac fi if test ! -f lex.yy.c; then echo 'main() { return 0; }' >lex.yy.c fi ;; help2man*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a dependency of a manual page. You may need the \`Help2man' package in order for those modifications to take effect. You can get \`Help2man' from any GNU archive site." file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -f "$file"; then touch $file else test -z "$file" || exec >$file echo ".ab help2man is required to generate this page" exit $? fi ;; makeinfo*) echo 1>&2 "\ WARNING: \`$1' is $msg. You should only need it if you modified a \`.texi' or \`.texinfo' file, or any other file indirectly affecting the aspect of the manual. The spurious call might also be the consequence of using a buggy \`make' (AIX, DU, IRIX). You might want to install the \`Texinfo' package or the \`GNU make' package. Grab either from any GNU archive site." # The file to touch is that specified with -o ... file=`echo "$*" | sed -n "$sed_output"` test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` if test -z "$file"; then # ... or it is the one specified with @setfilename ... infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` file=`sed -n ' /^@setfilename/{ s/.* \([^ ]*\) *$/\1/ p q }' $infile` # ... or it is derived from the source name (dir/f.texi becomes f.info) test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info fi # If the file does not exist, the user really needs makeinfo; # let's fail without touching anything. test -f $file || exit 1 touch $file ;; *) echo 1>&2 "\ WARNING: \`$1' is needed, and is $msg. You might have modified some files without having the proper tools for further handling them. Check the \`README' file, it often tells you about the needed prerequisites for installing this package. You may also peek at any GNU archive site, in case some other package would contain this missing \`$1' program." exit 1 ;; esac exit 0 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: bluez-4.101/configure.ac0000644000000000000000000000257111771117441012026 00000000000000AC_PREREQ(2.60) AC_INIT(bluez, 4.101) AM_INIT_AUTOMAKE([foreign subdir-objects color-tests]) AM_CONFIG_HEADER(config.h) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AM_MAINTAINER_MODE PKG_PROG_PKG_CONFIG AC_INIT_BLUEZ COMPILER_FLAGS AC_LANG_C AC_PROG_CC AM_PROG_CC_C_O AC_PROG_CC_PIE AC_PROG_INSTALL AC_PROG_YACC AM_PROG_LEX AM_PROG_MKDIR_P m4_define([_LT_AC_TAGCONFIG], []) m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])]) AC_DISABLE_STATIC AC_PROG_LIBTOOL AC_FUNC_PPOLL AC_CHECK_LIB(dl, dlopen, dummy=yes, AC_MSG_ERROR(dynamic linking loader is required)) AC_CHECK_HEADER([sys/inotify.h], [AC_DEFINE([HAVE_SYS_INOTIFY_H], 1, [Define to 1 if you have .])], [AC_MSG_ERROR(inotify headers are required and missing)]) AC_PATH_DBUS AC_PATH_GLIB AC_PATH_ALSA AC_PATH_GSTREAMER AC_PATH_USB AC_PATH_UDEV AC_PATH_SNDFILE AC_PATH_OUI AC_PATH_READLINE AC_PATH_CHECK AC_ARG_BLUEZ AC_ARG_WITH([systemdunitdir], AC_HELP_STRING([--with-systemdunitdir=DIR], [path to systemd system service directory]), [path_systemdunit=${withval}], [path_systemdunit="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"]) if (test -n "${path_systemdunit}"); then SYSTEMD_UNITDIR="${path_systemdunit}" AC_SUBST(SYSTEMD_UNITDIR) fi AM_CONDITIONAL(SYSTEMD, test -n "${path_systemdunit}") AC_OUTPUT(Makefile doc/version.xml src/bluetoothd.8 src/bluetooth.service bluez.pc) bluez-4.101/alert/0000755000000000000000000000000011771120004010707 500000000000000bluez-4.101/alert/server.c0000644000000000000000000000202611766125764012327 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include "server.h" int alert_server_init(void) { return 0; } void alert_server_exit(void) { } bluez-4.101/alert/main.c0000644000000000000000000000262411766125764011751 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "plugin.h" #include "hcid.h" #include "log.h" #include "server.h" static int alert_init(void) { if (!main_opts.gatt_enabled) { DBG("GATT is disabled"); return -ENOTSUP; } return alert_server_init(); } static void alert_exit(void) { if (!main_opts.gatt_enabled) return; alert_server_exit(); } BLUETOOTH_PLUGIN_DEFINE(alert, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, alert_init, alert_exit) bluez-4.101/alert/server.h0000644000000000000000000000167611766125764012346 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int alert_server_init(void); void alert_server_exit(void); bluez-4.101/input/0000755000000000000000000000000011771120005010740 500000000000000bluez-4.101/input/fakehid.h0000644000000000000000000000262211571052274012440 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ struct fake_hid; struct fake_input; struct fake_hid { uint16_t vendor; uint16_t product; gboolean (*connect) (struct fake_input *fake_input, GError **err); int (*disconnect) (struct fake_input *fake_input); gboolean (*event) (GIOChannel *chan, GIOCondition cond, gpointer data); int (*setup_uinput) (struct fake_input *fake, struct fake_hid *fake_hid); GList *devices; }; struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product); struct fake_input *fake_hid_connadd(struct fake_input *fake, GIOChannel *intr_io, struct fake_hid *fake_hid); bluez-4.101/input/server.c0000644000000000000000000001320211766125764012355 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "log.h" #include "glib-helper.h" #include "btio.h" #include "adapter.h" #include "device.h" #include "server.h" static GSList *servers = NULL; struct input_server { bdaddr_t src; GIOChannel *ctrl; GIOChannel *intr; GIOChannel *confirm; }; static gint server_cmp(gconstpointer s, gconstpointer user_data) { const struct input_server *server = s; const bdaddr_t *src = user_data; return bacmp(&server->src, src); } static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data) { uint16_t psm; bdaddr_t src, dst; char address[18]; GError *gerr = NULL; int ret; if (err) { error("%s", err->message); return; } bt_io_get(chan, BT_IO_L2CAP, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_PSM, &psm, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); g_io_channel_shutdown(chan, TRUE, NULL); return; } ba2str(&dst, address); DBG("Incoming connection from %s on PSM %d", address, psm); ret = input_device_set_channel(&src, &dst, psm, chan); if (ret == 0) return; error("Refusing input device connect: %s (%d)", strerror(-ret), -ret); /* Send unplug virtual cable to unknown devices */ if (ret == -ENOENT && psm == L2CAP_PSM_HIDP_CTRL) { unsigned char unplug = 0x15; int sk = g_io_channel_unix_get_fd(chan); if (write(sk, &unplug, sizeof(unplug)) < 0) error("Unable to send virtual cable unplug"); } g_io_channel_shutdown(chan, TRUE, NULL); } static void auth_callback(DBusError *derr, void *user_data) { struct input_server *server = user_data; bdaddr_t src, dst; GError *err = NULL; bt_io_get(server->confirm, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto reject; } if (derr) { error("Access denied: %s", derr->message); goto reject; } if (!bt_io_accept(server->confirm, connect_event_cb, server, NULL, &err)) { error("bt_io_accept: %s", err->message); g_error_free(err); goto reject; } g_io_channel_unref(server->confirm); server->confirm = NULL; return; reject: g_io_channel_shutdown(server->confirm, TRUE, NULL); g_io_channel_unref(server->confirm); server->confirm = NULL; input_device_close_channels(&src, &dst); } static void confirm_event_cb(GIOChannel *chan, gpointer user_data) { struct input_server *server = user_data; bdaddr_t src, dst; GError *err = NULL; char addr[18]; int ret; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } if (server->confirm) { char address[18]; ba2str(&dst, address); error("Refusing connection from %s: setup in progress", address); goto drop; } server->confirm = g_io_channel_ref(chan); ret = btd_request_authorization(&src, &dst, HID_UUID, auth_callback, server); if (ret == 0) return; ba2str(&src, addr); error("input: authorization for %s failed: %s (%d)", addr, strerror(-ret), ret); g_io_channel_unref(server->confirm); server->confirm = NULL; drop: input_device_close_channels(&src, &dst); g_io_channel_shutdown(chan, TRUE, NULL); } int server_start(const bdaddr_t *src) { struct input_server *server; GError *err = NULL; server = g_new0(struct input_server, 1); bacpy(&server->src, src); server->ctrl = bt_io_listen(BT_IO_L2CAP, connect_event_cb, NULL, server, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (!server->ctrl) { error("Failed to listen on control channel"); g_error_free(err); g_free(server); return -1; } server->intr = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event_cb, server, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (!server->intr) { error("Failed to listen on interrupt channel"); g_io_channel_unref(server->ctrl); g_error_free(err); g_free(server); return -1; } servers = g_slist_append(servers, server); return 0; } void server_stop(const bdaddr_t *src) { struct input_server *server; GSList *l; l = g_slist_find_custom(servers, src, server_cmp); if (!l) return; server = l->data; g_io_channel_shutdown(server->intr, TRUE, NULL); g_io_channel_unref(server->intr); g_io_channel_shutdown(server->ctrl, TRUE, NULL); g_io_channel_unref(server->ctrl); servers = g_slist_remove(servers, server); g_free(server); } bluez-4.101/input/fakehid.c0000644000000000000000000002213611766125764012450 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "../src/adapter.h" #include "../src/device.h" #include "log.h" #include "device.h" #include "fakehid.h" #include "uinput.h" enum ps3remote_special_keys { PS3R_BIT_PS = 0, PS3R_BIT_ENTER = 3, PS3R_BIT_L2 = 8, PS3R_BIT_R2 = 9, PS3R_BIT_L1 = 10, PS3R_BIT_R1 = 11, PS3R_BIT_TRIANGLE = 12, PS3R_BIT_CIRCLE = 13, PS3R_BIT_CROSS = 14, PS3R_BIT_SQUARE = 15, PS3R_BIT_SELECT = 16, PS3R_BIT_L3 = 17, PS3R_BIT_R3 = 18, PS3R_BIT_START = 19, PS3R_BIT_UP = 20, PS3R_BIT_RIGHT = 21, PS3R_BIT_DOWN = 22, PS3R_BIT_LEFT = 23, }; static unsigned int ps3remote_bits[] = { [PS3R_BIT_ENTER] = 0x0b, [PS3R_BIT_PS] = 0x43, [PS3R_BIT_SQUARE] = 0x5f, [PS3R_BIT_CROSS] = 0x5e, [PS3R_BIT_CIRCLE] = 0x5d, [PS3R_BIT_TRIANGLE] = 0x5c, [PS3R_BIT_R1] = 0x5b, [PS3R_BIT_L1] = 0x5a, [PS3R_BIT_R2] = 0x59, [PS3R_BIT_L2] = 0x58, [PS3R_BIT_LEFT] = 0x57, [PS3R_BIT_DOWN] = 0x56, [PS3R_BIT_RIGHT] = 0x55, [PS3R_BIT_UP] = 0x54, [PS3R_BIT_START] = 0x53, [PS3R_BIT_R3] = 0x52, [PS3R_BIT_L3] = 0x51, [PS3R_BIT_SELECT] = 0x50, }; static unsigned int ps3remote_keymap[] = { [0x16] = KEY_EJECTCD, [0x64] = KEY_AUDIO, [0x65] = KEY_ANGLE, [0x63] = KEY_SUBTITLE, [0x0f] = KEY_CLEAR, [0x28] = KEY_TIME, [0x00] = KEY_1, [0x01] = KEY_2, [0x02] = KEY_3, [0x03] = KEY_4, [0x04] = KEY_5, [0x05] = KEY_6, [0x06] = KEY_7, [0x07] = KEY_8, [0x08] = KEY_9, [0x09] = KEY_0, [0x81] = KEY_RED, [0x82] = KEY_GREEN, [0x80] = KEY_BLUE, [0x83] = KEY_YELLOW, [0x70] = KEY_INFO, /* display */ [0x1a] = KEY_MENU, /* top menu */ [0x40] = KEY_CONTEXT_MENU, /* pop up/menu */ [0x0e] = KEY_ESC, /* return */ [0x5c] = KEY_OPTION, /* options/triangle */ [0x5d] = KEY_BACK, /* back/circle */ [0x5f] = KEY_SCREEN, /* view/square */ [0x5e] = BTN_0, /* cross */ [0x54] = KEY_UP, [0x56] = KEY_DOWN, [0x57] = KEY_LEFT, [0x55] = KEY_RIGHT, [0x0b] = KEY_ENTER, [0x5a] = BTN_TL, /* L1 */ [0x58] = BTN_TL2, /* L2 */ [0x51] = BTN_THUMBL, /* L3 */ [0x5b] = BTN_TR, /* R1 */ [0x59] = BTN_TR2, /* R2 */ [0x52] = BTN_THUMBR, /* R3 */ [0x43] = KEY_HOMEPAGE, /* PS button */ [0x50] = KEY_SELECT, [0x53] = BTN_START, [0x33] = KEY_REWIND, /* scan back */ [0x32] = KEY_PLAY, [0x34] = KEY_FORWARD, /* scan forward */ [0x30] = KEY_PREVIOUS, [0x38] = KEY_STOP, [0x31] = KEY_NEXT, [0x60] = KEY_FRAMEBACK, /* slow/step back */ [0x39] = KEY_PAUSE, [0x61] = KEY_FRAMEFORWARD, /* slow/step forward */ [0xff] = KEY_MAX, }; static int ps3remote_decode(char *buff, int size, unsigned int *value) { static unsigned int lastkey = 0; static unsigned int lastmask = 0; unsigned int i, mask; int retval; guint8 key; if (size < 12) { error("Got a shorter packet! (size %i)\n", size); return KEY_RESERVED; } mask = (buff[2] << 16) + (buff[3] << 8) + buff[4]; key = buff[5]; /* first, check flags */ for (i = 0; i < 24; i++) { if ((lastmask & (1 << i)) == (mask & (1 << i))) continue; if (ps3remote_bits[i] == 0) goto error; retval = ps3remote_keymap[ps3remote_bits[i]]; if (mask & (1 << i)) /* key pressed */ *value = 1; else /* key released */ *value = 0; goto out; } *value = buff[11]; if (buff[11] == 1) { retval = ps3remote_keymap[key]; } else retval = lastkey; if (retval == KEY_RESERVED) goto error; if (retval == KEY_MAX) return retval; lastkey = retval; out: fflush(stdout); lastmask = mask; return retval; error: error("ps3remote: unrecognized sequence [%#x][%#x][%#x][%#x] [%#x]," "last: [%#x][%#x][%#x][%#x]", buff[2], buff[3], buff[4], buff[5], buff[11], lastmask >> 16, lastmask >> 8 & 0xff, lastmask & 0xff, lastkey); return -1; } static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond, gpointer data) { struct fake_input *fake = data; struct uinput_event event; unsigned int key, value = 0; ssize_t size; char buff[50]; int fd; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { error("Hangup or error on rfcomm server socket"); goto failed; } fd = g_io_channel_unix_get_fd(chan); memset(buff, 0, sizeof(buff)); size = read(fd, buff, sizeof(buff)); if (size < 0) { error("IO Channel read error"); goto failed; } key = ps3remote_decode(buff, size, &value); if (key == KEY_RESERVED) { error("Got invalid key from decode"); goto failed; } else if (key == KEY_MAX) return TRUE; memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_KEY; event.code = key; event.value = value; if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) { error("Error writing to uinput device"); goto failed; } memset(&event, 0, sizeof(event)); gettimeofday(&event.time, NULL); event.type = EV_SYN; event.code = SYN_REPORT; if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) { error("Error writing to uinput device"); goto failed; } return TRUE; failed: ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); fake->uinput = -1; g_io_channel_unref(fake->io); return FALSE; } static int ps3remote_setup_uinput(struct fake_input *fake, struct fake_hid *fake_hid) { struct uinput_dev dev; int i; fake->uinput = open("/dev/input/uinput", O_RDWR); if (fake->uinput < 0) { fake->uinput = open("/dev/uinput", O_RDWR); if (fake->uinput < 0) { fake->uinput = open("/dev/misc/uinput", O_RDWR); if (fake->uinput < 0) { error("Error opening uinput device file"); return 1; } } } memset(&dev, 0, sizeof(dev)); snprintf(dev.name, sizeof(dev.name), "%s", "PS3 Remote Controller"); dev.id.bustype = BUS_BLUETOOTH; dev.id.vendor = fake_hid->vendor; dev.id.product = fake_hid->product; if (write(fake->uinput, &dev, sizeof(dev)) != sizeof(dev)) { error("Error creating uinput device"); goto err; } /* enabling key events */ if (ioctl(fake->uinput, UI_SET_EVBIT, EV_KEY) < 0) { error("Error enabling uinput device key events"); goto err; } /* enabling keys */ for (i = 0; i < 256; i++) if (ps3remote_keymap[i] != KEY_RESERVED) if (ioctl(fake->uinput, UI_SET_KEYBIT, ps3remote_keymap[i]) < 0) { error("Error enabling uinput key %i", ps3remote_keymap[i]); goto err; } /* creating the device */ if (ioctl(fake->uinput, UI_DEV_CREATE) < 0) { error("Error creating uinput device"); goto err; } return 0; err: close(fake->uinput); return 1; } static gboolean fake_hid_common_connect(struct fake_input *fake, GError **err) { return TRUE; } static int fake_hid_common_disconnect(struct fake_input *fake) { return 0; } static struct fake_hid fake_hid_table[] = { /* Sony PS3 remote device */ { .vendor = 0x054c, .product = 0x0306, .connect = fake_hid_common_connect, .disconnect = fake_hid_common_disconnect, .event = ps3remote_event, .setup_uinput = ps3remote_setup_uinput, .devices = NULL, }, { }, }; static inline int fake_hid_match_device(uint16_t vendor, uint16_t product, struct fake_hid *fhid) { return vendor == fhid->vendor && product == fhid->product; } struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product) { int i; for (i = 0; fake_hid_table[i].vendor != 0; i++) if (fake_hid_match_device(vendor, product, &fake_hid_table[i])) return &fake_hid_table[i]; return NULL; } struct fake_input *fake_hid_connadd(struct fake_input *fake, GIOChannel *intr_io, struct fake_hid *fake_hid) { GList *l; struct fake_input *old = NULL; /* Look for an already setup device */ for (l = fake_hid->devices; l != NULL; l = l->next) { old = l->data; if (old->idev == fake->idev) { g_free(fake); fake = old; fake_hid->connect(fake, NULL); break; } old = NULL; } /* New device? Add it to the list of known devices, * and create the uinput necessary */ if (old == NULL || old->uinput < 0) { if (fake_hid->setup_uinput(fake, fake_hid)) { error("Error setting up uinput"); g_free(fake); return NULL; } } if (old == NULL) fake_hid->devices = g_list_append(fake_hid->devices, fake); fake->io = g_io_channel_ref(intr_io); g_io_channel_set_close_on_unref(fake->io, TRUE); g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) fake_hid->event, fake); return fake; } bluez-4.101/input/device.c0000644000000000000000000007244711766125764012326 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "uinput.h" #include "../src/adapter.h" #include "../src/device.h" #include "../src/storage.h" #include "../src/manager.h" #include "../src/dbus-common.h" #include "device.h" #include "error.h" #include "fakehid.h" #include "btio.h" #include "sdp-client.h" #define INPUT_DEVICE_INTERFACE "org.bluez.Input" #define BUF_SIZE 16 #define UPDOWN_ENABLED 1 #define FI_FLAG_CONNECTED 1 struct input_conn { struct fake_input *fake; DBusMessage *pending_connect; char *uuid; GIOChannel *ctrl_io; GIOChannel *intr_io; guint ctrl_watch; guint intr_watch; guint sec_watch; int timeout; struct hidp_connadd_req *req; struct input_device *idev; }; struct input_device { DBusConnection *conn; char *path; bdaddr_t src; bdaddr_t dst; uint32_t handle; guint dc_id; gboolean disable_sdp; char *name; struct btd_device *device; GSList *connections; }; static GSList *devices = NULL; static struct input_device *find_device_by_path(GSList *list, const char *path) { for (; list; list = list->next) { struct input_device *idev = list->data; if (!strcmp(idev->path, path)) return idev; } return NULL; } static struct input_conn *find_connection(GSList *list, const char *pattern) { for (; list; list = list->next) { struct input_conn *iconn = list->data; if (!strcasecmp(iconn->uuid, pattern)) return iconn; } return NULL; } static void input_conn_free(struct input_conn *iconn) { if (iconn->pending_connect) dbus_message_unref(iconn->pending_connect); if (iconn->ctrl_watch) g_source_remove(iconn->ctrl_watch); if (iconn->intr_watch) g_source_remove(iconn->intr_watch); if (iconn->sec_watch) g_source_remove(iconn->sec_watch); if (iconn->intr_io) g_io_channel_unref(iconn->intr_io); if (iconn->ctrl_io) g_io_channel_unref(iconn->ctrl_io); g_free(iconn->uuid); g_free(iconn->fake); g_free(iconn); } static void input_device_free(struct input_device *idev) { if (idev->dc_id) device_remove_disconnect_watch(idev->device, idev->dc_id); dbus_connection_unref(idev->conn); btd_device_unref(idev->device); g_free(idev->name); g_free(idev->path); g_free(idev); } static int uinput_create(char *name) { struct uinput_dev dev; int fd, err; fd = open("/dev/uinput", O_RDWR); if (fd < 0) { fd = open("/dev/input/uinput", O_RDWR); if (fd < 0) { fd = open("/dev/misc/uinput", O_RDWR); if (fd < 0) { err = -errno; error("Can't open input device: %s (%d)", strerror(-err), -err); return err; } } } memset(&dev, 0, sizeof(dev)); if (name) strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1); dev.id.bustype = BUS_BLUETOOTH; dev.id.vendor = 0x0000; dev.id.product = 0x0000; dev.id.version = 0x0000; if (write(fd, &dev, sizeof(dev)) < 0) { err = -errno; error("Can't write device information: %s (%d)", strerror(-err), -err); close(fd); return err; } ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_REL); ioctl(fd, UI_SET_EVBIT, EV_REP); ioctl(fd, UI_SET_KEYBIT, KEY_UP); ioctl(fd, UI_SET_KEYBIT, KEY_PAGEUP); ioctl(fd, UI_SET_KEYBIT, KEY_DOWN); ioctl(fd, UI_SET_KEYBIT, KEY_PAGEDOWN); if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) { err = -errno; error("Can't create uinput device: %s (%d)", strerror(-err), -err); close(fd); return err; } return fd; } static int decode_key(const char *str) { static int mode = UPDOWN_ENABLED, gain = 0; uint16_t key; int new_gain; /* Switch from key up/down to page up/down */ if (strncmp("AT+CKPD=200", str, 11) == 0) { mode = ~mode; return KEY_RESERVED; } if (strncmp("AT+VG", str, 5)) return KEY_RESERVED; /* Gain key pressed */ if (strlen(str) != 10) return KEY_RESERVED; new_gain = strtol(&str[7], NULL, 10); if (new_gain <= gain) key = (mode == UPDOWN_ENABLED ? KEY_UP : KEY_PAGEUP); else key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN); gain = new_gain; return key; } static int send_event(int fd, uint16_t type, uint16_t code, int32_t value) { struct uinput_event event; memset(&event, 0, sizeof(event)); event.type = type; event.code = code; event.value = value; return write(fd, &event, sizeof(event)); } static void send_key(int fd, uint16_t key) { /* Key press */ send_event(fd, EV_KEY, key, 1); send_event(fd, EV_SYN, SYN_REPORT, 0); /* Key release */ send_event(fd, EV_KEY, key, 0); send_event(fd, EV_SYN, SYN_REPORT, 0); } static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct fake_input *fake = data; const char *ok = "\r\nOK\r\n"; char buf[BUF_SIZE]; ssize_t bread = 0, bwritten; uint16_t key; int fd; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { error("Hangup or error on rfcomm server socket"); goto failed; } fd = g_io_channel_unix_get_fd(chan); memset(buf, 0, BUF_SIZE); bread = read(fd, buf, sizeof(buf) - 1); if (bread < 0) { error("IO Channel read error"); goto failed; } DBG("Received: %s", buf); bwritten = write(fd, ok, 6); if (bwritten < 0) { error("IO Channel write error"); goto failed; } key = decode_key(buf); if (key != KEY_RESERVED) send_key(fake->uinput, key); return TRUE; failed: ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); fake->uinput = -1; g_io_channel_unref(fake->io); return FALSE; } static void rfcomm_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct input_conn *iconn = user_data; struct input_device *idev = iconn->idev; struct fake_input *fake = iconn->fake; DBusMessage *reply; if (err) { reply = btd_error_failed(iconn->pending_connect, err->message); goto failed; } fake->rfcomm = g_io_channel_unix_get_fd(chan); /* * FIXME: Some headsets required a sco connection * first to report volume gain key events */ fake->uinput = uinput_create(idev->name); if (fake->uinput < 0) { int err = fake->uinput; g_io_channel_shutdown(chan, TRUE, NULL); reply = btd_error_failed(iconn->pending_connect, strerror(-err)); goto failed; } fake->io = g_io_channel_unix_new(fake->rfcomm); g_io_channel_set_close_on_unref(fake->io, TRUE); g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_io_cb, fake); /* Replying to the requestor */ reply = dbus_message_new_method_return(iconn->pending_connect); g_dbus_send_message(idev->conn, reply); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; return; failed: g_dbus_send_message(idev->conn, reply); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; } static gboolean rfcomm_connect(struct input_conn *iconn, GError **err) { struct input_device *idev = iconn->idev; GIOChannel *io; io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, iconn, NULL, err, BT_IO_OPT_SOURCE_BDADDR, &idev->src, BT_IO_OPT_DEST_BDADDR, &idev->dst, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID); if (!io) return FALSE; g_io_channel_unref(io); return TRUE; } static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct input_conn *iconn = data; struct input_device *idev = iconn->idev; gboolean connected = FALSE; /* Checking for ctrl_watch avoids a double g_io_channel_shutdown since * it's likely that ctrl_watch_cb has been queued for dispatching in * this mainloop iteration */ if ((cond & (G_IO_HUP | G_IO_ERR)) && iconn->ctrl_watch) g_io_channel_shutdown(chan, TRUE, NULL); emit_property_changed(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &connected); device_remove_disconnect_watch(idev->device, idev->dc_id); idev->dc_id = 0; iconn->intr_watch = 0; g_io_channel_unref(iconn->intr_io); iconn->intr_io = NULL; /* Close control channel */ if (iconn->ctrl_io && !(cond & G_IO_NVAL)) g_io_channel_shutdown(iconn->ctrl_io, TRUE, NULL); return FALSE; } static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct input_conn *iconn = data; /* Checking for intr_watch avoids a double g_io_channel_shutdown since * it's likely that intr_watch_cb has been queued for dispatching in * this mainloop iteration */ if ((cond & (G_IO_HUP | G_IO_ERR)) && iconn->intr_watch) g_io_channel_shutdown(chan, TRUE, NULL); iconn->ctrl_watch = 0; g_io_channel_unref(iconn->ctrl_io); iconn->ctrl_io = NULL; /* Close interrupt channel */ if (iconn->intr_io && !(cond & G_IO_NVAL)) g_io_channel_shutdown(iconn->intr_io, TRUE, NULL); return FALSE; } static gboolean fake_hid_connect(struct input_conn *iconn, GError **err) { struct fake_hid *fhid = iconn->fake->priv; return fhid->connect(iconn->fake, err); } static int fake_hid_disconnect(struct input_conn *iconn) { struct fake_hid *fhid = iconn->fake->priv; return fhid->disconnect(iconn->fake); } static void epox_endian_quirk(unsigned char *data, int size) { /* USAGE_PAGE (Keyboard) 05 07 * USAGE_MINIMUM (0) 19 00 * USAGE_MAXIMUM (65280) 2A 00 FF <= must be FF 00 * LOGICAL_MINIMUM (0) 15 00 * LOGICAL_MAXIMUM (65280) 26 00 FF <= must be FF 00 */ unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff, 0x15, 0x00, 0x26, 0x00, 0xff }; unsigned int i; if (!data) return; for (i = 0; i < size - sizeof(pattern); i++) { if (!memcmp(data + i, pattern, sizeof(pattern))) { data[i + 5] = 0xff; data[i + 6] = 0x00; data[i + 10] = 0xff; data[i + 11] = 0x00; } } } static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *pdlist, *pdlist2; uint8_t attr_val; pdlist = sdp_data_get(rec, 0x0101); pdlist2 = sdp_data_get(rec, 0x0102); if (pdlist) { if (pdlist2) { if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) { strncpy(req->name, pdlist2->val.str, 127); strcat(req->name, " "); } strncat(req->name, pdlist->val.str, 127 - strlen(req->name)); } else strncpy(req->name, pdlist->val.str, 127); } else { pdlist2 = sdp_data_get(rec, 0x0100); if (pdlist2) strncpy(req->name, pdlist2->val.str, 127); } pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION); req->parser = pdlist ? pdlist->val.uint16 : 0x0100; pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS); req->subclass = pdlist ? pdlist->val.uint8 : 0; pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE); req->country = pdlist ? pdlist->val.uint8 : 0; pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE); attr_val = pdlist ? pdlist->val.uint8 : 0; if (attr_val) req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG); pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE); attr_val = pdlist ? pdlist->val.uint8 : 0; if (attr_val) req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE); pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST); if (pdlist) { pdlist = pdlist->val.dataseq; pdlist = pdlist->val.dataseq; pdlist = pdlist->next; req->rd_data = g_try_malloc0(pdlist->unitSize); if (req->rd_data) { memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); req->rd_size = pdlist->unitSize; epox_endian_quirk(req->rd_data, req->rd_size); } } } static int ioctl_connadd(struct hidp_connadd_req *req) { int ctl, err = 0; ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) return -errno; if (ioctl(ctl, HIDPCONNADD, req) < 0) err = -errno; close(ctl); return err; } static void encrypt_completed(uint8_t status, gpointer user_data) { struct hidp_connadd_req *req = user_data; int err; if (status) { error("Encryption failed: %s(0x%x)", strerror(bt_error(status)), status); goto failed; } err = ioctl_connadd(req); if (err == 0) goto cleanup; error("ioctl_connadd(): %s(%d)", strerror(-err), -err); failed: close(req->intr_sock); close(req->ctrl_sock); cleanup: free(req->rd_data); g_free(req); } static gboolean encrypt_notify(GIOChannel *io, GIOCondition condition, gpointer data) { struct input_conn *iconn = data; struct hidp_connadd_req *req = iconn->req; DBG(" "); encrypt_completed(0, req); iconn->sec_watch = 0; iconn->req = NULL; return FALSE; } static int hidp_add_connection(const struct input_device *idev, struct input_conn *iconn) { struct hidp_connadd_req *req; struct fake_hid *fake_hid; struct fake_input *fake; sdp_record_t *rec; char src_addr[18], dst_addr[18]; GError *gerr = NULL; int err; req = g_new0(struct hidp_connadd_req, 1); req->ctrl_sock = g_io_channel_unix_get_fd(iconn->ctrl_io); req->intr_sock = g_io_channel_unix_get_fd(iconn->intr_io); req->flags = 0; req->idle_to = iconn->timeout; ba2str(&idev->src, src_addr); ba2str(&idev->dst, dst_addr); rec = fetch_record(src_addr, dst_addr, idev->handle); if (!rec) { error("Rejected connection from unknown device %s", dst_addr); err = -EPERM; goto cleanup; } extract_hid_record(rec, req); sdp_record_free(rec); req->vendor = btd_device_get_vendor(idev->device); req->product = btd_device_get_product(idev->device); req->version = btd_device_get_version(idev->device); fake_hid = get_fake_hid(req->vendor, req->product); if (fake_hid) { err = 0; fake = g_new0(struct fake_input, 1); fake->connect = fake_hid_connect; fake->disconnect = fake_hid_disconnect; fake->priv = fake_hid; fake->idev = idev; fake = fake_hid_connadd(fake, iconn->intr_io, fake_hid); if (fake == NULL) err = -ENOMEM; else fake->flags |= FI_FLAG_CONNECTED; goto cleanup; } if (idev->name) strncpy(req->name, idev->name, sizeof(req->name) - 1); /* Encryption is mandatory for keyboards */ if (req->subclass & 0x40) { struct btd_adapter *adapter = device_get_adapter(idev->device); err = btd_adapter_encrypt_link(adapter, (bdaddr_t *) &idev->dst, encrypt_completed, req); if (err == 0) { /* Waiting async encryption */ return 0; } if (err == -ENOSYS) goto nosys; if (err != -EALREADY) { error("encrypt_link: %s (%d)", strerror(-err), -err); goto cleanup; } } err = ioctl_connadd(req); cleanup: free(req->rd_data); g_free(req); return err; nosys: if (!bt_io_set(iconn->intr_io, BT_IO_L2CAP, &gerr, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID)) { error("btio: %s", gerr->message); g_error_free(gerr); goto cleanup; } iconn->req = req; iconn->sec_watch = g_io_add_watch(iconn->intr_io, G_IO_OUT, encrypt_notify, iconn); return 0; } static int is_connected(struct input_conn *iconn) { struct input_device *idev = iconn->idev; struct fake_input *fake = iconn->fake; struct hidp_conninfo ci; int ctl; /* Fake input */ if (fake) return fake->flags & FI_FLAG_CONNECTED; /* Standard HID */ ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) return 0; memset(&ci, 0, sizeof(ci)); bacpy(&ci.bdaddr, &idev->dst); if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) { close(ctl); return 0; } close(ctl); if (ci.state != BT_CONNECTED) return 0; else return 1; } static int connection_disconnect(struct input_conn *iconn, uint32_t flags) { struct input_device *idev = iconn->idev; struct fake_input *fake = iconn->fake; struct hidp_conndel_req req; struct hidp_conninfo ci; int ctl, err = 0; /* Fake input disconnect */ if (fake) { err = fake->disconnect(iconn); if (err == 0) fake->flags &= ~FI_FLAG_CONNECTED; return err; } /* Standard HID disconnect */ if (iconn->intr_io) g_io_channel_shutdown(iconn->intr_io, TRUE, NULL); if (iconn->ctrl_io) g_io_channel_shutdown(iconn->ctrl_io, TRUE, NULL); ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP); if (ctl < 0) { error("Can't open HIDP control socket"); return -errno; } memset(&ci, 0, sizeof(ci)); bacpy(&ci.bdaddr, &idev->dst); if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) || (ci.state != BT_CONNECTED)) { err = -ENOTCONN; goto fail; } memset(&req, 0, sizeof(req)); bacpy(&req.bdaddr, &idev->dst); req.flags = flags; if (ioctl(ctl, HIDPCONNDEL, &req) < 0) { err = -errno; error("Can't delete the HID device: %s(%d)", strerror(-err), -err); goto fail; } fail: close(ctl); return err; } static int disconnect(struct input_device *idev, uint32_t flags) { struct input_conn *iconn = NULL; GSList *l; for (l = idev->connections; l; l = l->next) { iconn = l->data; if (is_connected(iconn)) break; } if (!iconn) return -ENOTCONN; return connection_disconnect(iconn, flags); } static void disconnect_cb(struct btd_device *device, gboolean removal, void *user_data) { struct input_device *idev = user_data; int flags; info("Input: disconnect %s", idev->path); flags = removal ? (1 << HIDP_VIRTUAL_CABLE_UNPLUG) : 0; disconnect(idev, flags); } static int input_device_connected(struct input_device *idev, struct input_conn *iconn) { dbus_bool_t connected; int err; if (iconn->intr_io == NULL || iconn->ctrl_io == NULL) return -ENOTCONN; err = hidp_add_connection(idev, iconn); if (err < 0) return err; iconn->intr_watch = g_io_add_watch(iconn->intr_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, intr_watch_cb, iconn); iconn->ctrl_watch = g_io_add_watch(iconn->ctrl_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL, ctrl_watch_cb, iconn); connected = TRUE; emit_property_changed(idev->conn, idev->path, INPUT_DEVICE_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &connected); idev->dc_id = device_add_disconnect_watch(idev->device, disconnect_cb, idev, NULL); return 0; } static void interrupt_connect_cb(GIOChannel *chan, GError *conn_err, gpointer user_data) { struct input_conn *iconn = user_data; struct input_device *idev = iconn->idev; DBusMessage *reply; int err; const char *err_msg; if (conn_err) { err_msg = conn_err->message; goto failed; } err = input_device_connected(idev, iconn); if (err < 0) { err_msg = strerror(-err); goto failed; } /* Replying to the requestor */ g_dbus_send_reply(idev->conn, iconn->pending_connect, DBUS_TYPE_INVALID); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; return; failed: error("%s", err_msg); reply = btd_error_failed(iconn->pending_connect, err_msg); g_dbus_send_message(idev->conn, reply); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; /* So we guarantee the interrupt channel is closed before the * control channel (if we only do unref GLib will close it only * after returning control to the mainloop */ if (!conn_err) g_io_channel_shutdown(iconn->intr_io, FALSE, NULL); g_io_channel_unref(iconn->intr_io); iconn->intr_io = NULL; if (iconn->ctrl_io) { g_io_channel_unref(iconn->ctrl_io); iconn->ctrl_io = NULL; } } static void control_connect_cb(GIOChannel *chan, GError *conn_err, gpointer user_data) { struct input_conn *iconn = user_data; struct input_device *idev = iconn->idev; DBusMessage *reply; GIOChannel *io; GError *err = NULL; if (conn_err) { error("%s", conn_err->message); reply = btd_error_failed(iconn->pending_connect, conn_err->message); goto failed; } /* Connect to the HID interrupt channel */ io = bt_io_connect(BT_IO_L2CAP, interrupt_connect_cb, iconn, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &idev->src, BT_IO_OPT_DEST_BDADDR, &idev->dst, BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (!io) { error("%s", err->message); reply = btd_error_failed(iconn->pending_connect, err->message); g_error_free(err); goto failed; } iconn->intr_io = io; return; failed: g_io_channel_unref(iconn->ctrl_io); iconn->ctrl_io = NULL; g_dbus_send_message(idev->conn, reply); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; } static int fake_disconnect(struct input_conn *iconn) { struct fake_input *fake = iconn->fake; if (!fake->io) return -ENOTCONN; g_io_channel_shutdown(fake->io, TRUE, NULL); g_io_channel_unref(fake->io); fake->io = NULL; if (fake->uinput >= 0) { ioctl(fake->uinput, UI_DEV_DESTROY); close(fake->uinput); fake->uinput = -1; } return 0; } /* * Input Device methods */ static DBusMessage *input_device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; struct input_conn *iconn; struct fake_input *fake; DBusMessage *reply; GError *err = NULL; iconn = find_connection(idev->connections, HID_UUID); if (!iconn) return btd_error_not_supported(msg); if (iconn->pending_connect) return btd_error_in_progress(msg); if (is_connected(iconn)) return btd_error_already_connected(msg); iconn->pending_connect = dbus_message_ref(msg); fake = iconn->fake; if (fake) { /* Fake input device */ if (fake->connect(iconn, &err)) fake->flags |= FI_FLAG_CONNECTED; } else { /* HID devices */ GIOChannel *io; if (idev->disable_sdp) bt_clear_cached_session(&idev->src, &idev->dst); io = bt_io_connect(BT_IO_L2CAP, control_connect_cb, iconn, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &idev->src, BT_IO_OPT_DEST_BDADDR, &idev->dst, BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); iconn->ctrl_io = io; } if (err == NULL) return NULL; error("%s", err->message); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; reply = btd_error_failed(msg, err->message); g_error_free(err); return reply; } static DBusMessage *input_device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; int err; err = disconnect(idev, 0); if (err < 0) return btd_error_failed(msg, strerror(-err)); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static void device_unregister(void *data) { struct input_device *idev = data; DBG("Unregistered interface %s on path %s", INPUT_DEVICE_INTERFACE, idev->path); devices = g_slist_remove(devices, idev); input_device_free(idev); } static gint connected_cmp(gpointer a, gpointer b) { struct input_conn *iconn = a; return !is_connected(iconn); } static DBusMessage *input_device_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; dbus_bool_t connected; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Connected */ connected = !!g_slist_find_custom(idev->connections, NULL, (GCompareFunc) connected_cmp); dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected); dbus_message_iter_close_container(&iter, &dict); return reply; } static const GDBusMethodTable device_methods[] = { { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, input_device_connect) }, { GDBUS_METHOD("Disconnect", NULL, NULL, input_device_disconnect) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), input_device_get_properties) }, { } }; static const GDBusSignalTable device_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static struct input_device *input_device_new(DBusConnection *conn, struct btd_device *device, const char *path, const uint32_t handle, gboolean disable_sdp) { struct btd_adapter *adapter = device_get_adapter(device); struct input_device *idev; char name[249], src_addr[18], dst_addr[18]; idev = g_new0(struct input_device, 1); adapter_get_address(adapter, &idev->src); device_get_address(device, &idev->dst, NULL); idev->device = btd_device_ref(device); idev->path = g_strdup(path); idev->conn = dbus_connection_ref(conn); idev->handle = handle; idev->disable_sdp = disable_sdp; ba2str(&idev->src, src_addr); ba2str(&idev->dst, dst_addr); if (read_device_name(src_addr, dst_addr, name) == 0) idev->name = g_strdup(name); if (g_dbus_register_interface(conn, idev->path, INPUT_DEVICE_INTERFACE, device_methods, device_signals, NULL, idev, device_unregister) == FALSE) { error("Failed to register interface %s on path %s", INPUT_DEVICE_INTERFACE, path); input_device_free(idev); return NULL; } DBG("Registered interface %s on path %s", INPUT_DEVICE_INTERFACE, idev->path); return idev; } static struct input_conn *input_conn_new(struct input_device *idev, const char *uuid, int timeout) { struct input_conn *iconn; iconn = g_new0(struct input_conn, 1); iconn->timeout = timeout; iconn->uuid = g_strdup(uuid); iconn->idev = idev; return iconn; } static gboolean is_device_sdp_disable(const sdp_record_t *rec) { sdp_data_t *data; data = sdp_data_get(rec, SDP_ATTR_HID_SDP_DISABLE); return data && data->val.uint8; } int input_device_register(DBusConnection *conn, struct btd_device *device, const char *path, const char *uuid, const sdp_record_t *rec, int timeout) { struct input_device *idev; struct input_conn *iconn; idev = find_device_by_path(devices, path); if (!idev) { idev = input_device_new(conn, device, path, rec->handle, is_device_sdp_disable(rec)); if (!idev) return -EINVAL; devices = g_slist_append(devices, idev); } iconn = input_conn_new(idev, uuid, timeout); idev->connections = g_slist_append(idev->connections, iconn); return 0; } int fake_input_register(DBusConnection *conn, struct btd_device *device, const char *path, const char *uuid, uint8_t channel) { struct input_device *idev; struct input_conn *iconn; idev = find_device_by_path(devices, path); if (!idev) { idev = input_device_new(conn, device, path, 0, FALSE); if (!idev) return -EINVAL; devices = g_slist_append(devices, idev); } iconn = input_conn_new(idev, uuid, 0); iconn->fake = g_new0(struct fake_input, 1); iconn->fake->ch = channel; iconn->fake->connect = rfcomm_connect; iconn->fake->disconnect = fake_disconnect; idev->connections = g_slist_append(idev->connections, iconn); return 0; } static struct input_device *find_device(const bdaddr_t *src, const bdaddr_t *dst) { GSList *list; for (list = devices; list != NULL; list = list->next) { struct input_device *idev = list->data; if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst)) return idev; } return NULL; } int input_device_unregister(const char *path, const char *uuid) { struct input_device *idev; struct input_conn *iconn; idev = find_device_by_path(devices, path); if (idev == NULL) return -EINVAL; iconn = find_connection(idev->connections, uuid); if (iconn == NULL) return -EINVAL; if (iconn->pending_connect) { /* Pending connection running */ return -EBUSY; } idev->connections = g_slist_remove(idev->connections, iconn); input_conn_free(iconn); if (idev->connections) return 0; g_dbus_unregister_interface(idev->conn, path, INPUT_DEVICE_INTERFACE); return 0; } static int input_device_connadd(struct input_device *idev, struct input_conn *iconn) { int err; err = input_device_connected(idev, iconn); if (err < 0) goto error; return 0; error: if (iconn->ctrl_io) { g_io_channel_shutdown(iconn->ctrl_io, FALSE, NULL); g_io_channel_unref(iconn->ctrl_io); iconn->ctrl_io = NULL; } if (iconn->intr_io) { g_io_channel_shutdown(iconn->intr_io, FALSE, NULL); g_io_channel_unref(iconn->intr_io); iconn->intr_io = NULL; } return err; } int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm, GIOChannel *io) { struct input_device *idev = find_device(src, dst); struct input_conn *iconn; if (!idev) return -ENOENT; iconn = find_connection(idev->connections, HID_UUID); if (!iconn) return -ENOENT; switch (psm) { case L2CAP_PSM_HIDP_CTRL: if (iconn->ctrl_io) return -EALREADY; iconn->ctrl_io = g_io_channel_ref(io); break; case L2CAP_PSM_HIDP_INTR: if (iconn->intr_io) return -EALREADY; iconn->intr_io = g_io_channel_ref(io); break; } if (iconn->intr_io && iconn->ctrl_io) input_device_connadd(idev, iconn); return 0; } int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst) { struct input_device *idev = find_device(src, dst); struct input_conn *iconn; if (!idev) return -ENOENT; iconn = find_connection(idev->connections, HID_UUID); if (!iconn) return -ENOENT; if (iconn->intr_io) g_io_channel_shutdown(iconn->intr_io, TRUE, NULL); if (iconn->ctrl_io) g_io_channel_shutdown(iconn->ctrl_io, TRUE, NULL); return 0; } bluez-4.101/input/input.conf0000644000000000000000000000040611071665350012700 00000000000000# Configuration file for the input service # This section contains options which are not specific to any # particular interface [General] # Set idle timeout (in minutes) before the connection will # be disconnect (defaults to 0 for no timeout) #IdleTimeout=30 bluez-4.101/input/device.h0000644000000000000000000000344711766125764012325 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define L2CAP_PSM_HIDP_CTRL 0x11 #define L2CAP_PSM_HIDP_INTR 0x13 struct input_device; struct input_conn; struct fake_input { int flags; GIOChannel *io; int uinput; /* uinput socket */ int rfcomm; /* RFCOMM socket */ uint8_t ch; /* RFCOMM channel number */ gboolean (*connect) (struct input_conn *iconn, GError **err); int (*disconnect) (struct input_conn *iconn); void *priv; const struct input_device *idev; }; int fake_input_register(DBusConnection *conn, struct btd_device *device, const char *path, const char *uuid, uint8_t channel); int input_device_register(DBusConnection *conn, struct btd_device *device, const char *path, const char *uuid, const sdp_record_t *rec, int timeout); int input_device_unregister(const char *path, const char *uuid); int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm, GIOChannel *io); int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst); bluez-4.101/input/main.c0000644000000000000000000000365511766125764012006 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include "plugin.h" #include "log.h" #include "manager.h" static GKeyFile *load_config_file(const char *file) { GKeyFile *keyfile; GError *err = NULL; keyfile = g_key_file_new(); if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { error("Parsing %s failed: %s", file, err->message); g_error_free(err); g_key_file_free(keyfile); return NULL; } return keyfile; } static DBusConnection *connection; static int input_init(void) { GKeyFile *config; connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (connection == NULL) return -EIO; config = load_config_file(CONFIGDIR "/input.conf"); if (input_manager_init(connection, config) < 0) { dbus_connection_unref(connection); return -EIO; } if (config) g_key_file_free(config); return 0; } static void input_exit(void) { input_manager_exit(); dbus_connection_unref(connection); } BLUETOOTH_PLUGIN_DEFINE(input, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, input_init, input_exit) bluez-4.101/input/manager.h0000644000000000000000000000167511376221745012472 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int input_manager_init(DBusConnection *conn, GKeyFile *config); void input_manager_exit(void); bluez-4.101/input/manager.c0000644000000000000000000001062511766125764012467 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "log.h" #include "../src/adapter.h" #include "../src/device.h" #include "device.h" #include "server.h" #include "manager.h" static int idle_timeout = 0; static DBusConnection *connection = NULL; static GSList *adapters = NULL; static void input_remove(struct btd_device *device, const char *uuid) { const gchar *path = device_get_path(device); DBG("path %s", path); input_device_unregister(path, uuid); } static int hid_device_probe(struct btd_device *device, GSList *uuids) { const gchar *path = device_get_path(device); const sdp_record_t *rec = btd_device_get_record(device, uuids->data); DBG("path %s", path); if (!rec) return -1; return input_device_register(connection, device, path, HID_UUID, rec, idle_timeout * 60); } static void hid_device_remove(struct btd_device *device) { input_remove(device, HID_UUID); } static int headset_probe(struct btd_device *device, GSList *uuids) { const gchar *path = device_get_path(device); const sdp_record_t *record; sdp_list_t *protos; int ch; DBG("path %s", path); if (!g_slist_find_custom(uuids, HSP_HS_UUID, (GCompareFunc) strcasecmp)) return -EINVAL; record = btd_device_get_record(device, uuids->data); if (!record || sdp_get_access_protos(record, &protos) < 0) { error("Invalid record"); return -EINVAL; } ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); if (ch <= 0) { error("Invalid RFCOMM channel"); return -EINVAL; } return fake_input_register(connection, device, path, HSP_HS_UUID, ch); } static void headset_remove(struct btd_device *device) { input_remove(device, HSP_HS_UUID); } static int hid_server_probe(struct btd_adapter *adapter) { bdaddr_t src; int ret; adapter_get_address(adapter, &src); ret = server_start(&src); if (ret < 0) return ret; adapters = g_slist_append(adapters, btd_adapter_ref(adapter)); return 0; } static void hid_server_remove(struct btd_adapter *adapter) { bdaddr_t src; adapter_get_address(adapter, &src); server_stop(&src); adapters = g_slist_remove(adapters, adapter); btd_adapter_unref(adapter); } static struct btd_device_driver input_hid_driver = { .name = "input-hid", .uuids = BTD_UUIDS(HID_UUID), .probe = hid_device_probe, .remove = hid_device_remove, }; static struct btd_device_driver input_headset_driver = { .name = "input-headset", .uuids = BTD_UUIDS(HSP_HS_UUID), .probe = headset_probe, .remove = headset_remove, }; static struct btd_adapter_driver input_server_driver = { .name = "input-server", .probe = hid_server_probe, .remove = hid_server_remove, }; int input_manager_init(DBusConnection *conn, GKeyFile *config) { GError *err = NULL; if (config) { idle_timeout = g_key_file_get_integer(config, "General", "IdleTimeout", &err); if (err) { DBG("input.conf: %s", err->message); g_error_free(err); } } connection = dbus_connection_ref(conn); btd_register_adapter_driver(&input_server_driver); btd_register_device_driver(&input_hid_driver); btd_register_device_driver(&input_headset_driver); return 0; } void input_manager_exit(void) { btd_unregister_device_driver(&input_hid_driver); btd_unregister_device_driver(&input_headset_driver); btd_unregister_adapter_driver(&input_server_driver); dbus_connection_unref(connection); connection = NULL; } bluez-4.101/input/server.h0000644000000000000000000000165411376221745012363 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int server_start(const bdaddr_t *src); void server_stop(const bdaddr_t *src); bluez-4.101/acinclude.m40000644000000000000000000003050211771117441011724 00000000000000AC_DEFUN([AC_PROG_CC_PIE], [ AC_CACHE_CHECK([whether ${CC-cc} accepts -fPIE], ac_cv_prog_cc_pie, [ echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then ac_cv_prog_cc_pie=yes else ac_cv_prog_cc_pie=no fi rm -rf conftest* ]) ]) AC_DEFUN([COMPILER_FLAGS], [ with_cflags="" if (test "$USE_MAINTAINER_MODE" = "yes"); then with_cflags="$with_cflags -Wall -Werror -Wextra" with_cflags="$with_cflags -Wno-unused-parameter" with_cflags="$with_cflags -Wno-missing-field-initializers" with_cflags="$with_cflags -Wdeclaration-after-statement" with_cflags="$with_cflags -Wmissing-declarations" with_cflags="$with_cflags -Wredundant-decls" with_cflags="$with_cflags -Wcast-align" with_cflags="$with_cflags -DG_DISABLE_DEPRECATED" fi AC_SUBST([WARNING_CFLAGS], $with_cflags) ]) AC_DEFUN([AC_FUNC_PPOLL], [ AC_CHECK_FUNC(ppoll, dummy=yes, AC_DEFINE(NEED_PPOLL, 1, [Define to 1 if you need the ppoll() function.])) ]) AC_DEFUN([AC_INIT_BLUEZ], [ AC_PREFIX_DEFAULT(/usr/local) if (test "${prefix}" = "NONE"); then dnl no prefix and no sysconfdir, so default to /etc if (test "$sysconfdir" = '${prefix}/etc'); then AC_SUBST([sysconfdir], ['/etc']) fi dnl no prefix and no localstatedir, so default to /var if (test "$localstatedir" = '${prefix}/var'); then AC_SUBST([localstatedir], ['/var']) fi dnl no prefix and no libexecdir, so default to /lib if (test "$libexecdir" = '${exec_prefix}/libexec'); then AC_SUBST([libexecdir], ['/lib']) fi dnl no prefix and no mandir, so use ${prefix}/share/man as default if (test "$mandir" = '${prefix}/man'); then AC_SUBST([mandir], ['${prefix}/share/man']) fi prefix="${ac_default_prefix}" fi if (test "${libdir}" = '${exec_prefix}/lib'); then libdir="${prefix}/lib" fi plugindir="${libdir}/bluetooth/plugins" if (test "$sysconfdir" = '${prefix}/etc'); then configdir="${prefix}/etc/bluetooth" else configdir="${sysconfdir}/bluetooth" fi if (test "$localstatedir" = '${prefix}/var'); then storagedir="${prefix}/var/lib/bluetooth" else storagedir="${localstatedir}/lib/bluetooth" fi AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}", [Directory for the configuration files]) AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}", [Directory for the storage files]) AC_SUBST(CONFIGDIR, "${configdir}") AC_SUBST(STORAGEDIR, "${storagedir}") UDEV_DIR="`$PKG_CONFIG --variable=udevdir udev`" if (test -z "${UDEV_DIR}"); then UDEV_DIR="/lib/udev" fi AC_SUBST(UDEV_DIR) ]) AC_DEFUN([AC_PATH_DBUS], [ PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.4, dummy=yes, AC_MSG_ERROR(D-Bus >= 1.4 is required)) AC_SUBST(DBUS_CFLAGS) AC_SUBST(DBUS_LIBS) ]) AC_DEFUN([AC_PATH_GLIB], [ PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.28, dummy=yes, AC_MSG_ERROR(GLib >= 2.28 is required)) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) ]) AC_DEFUN([AC_PATH_GSTREAMER], [ PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10, gstreamer_found=yes, AC_MSG_WARN(GStreamer library version 0.10.30 or later is required);gstreamer_found=no) AC_SUBST(GSTREAMER_CFLAGS) AC_SUBST(GSTREAMER_LIBS) GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10` AC_SUBST(GSTREAMER_PLUGINSDIR) ]) AC_DEFUN([AC_PATH_ALSA], [ PKG_CHECK_MODULES(ALSA, alsa, alsa_found=yes, alsa_found=no) AC_CHECK_LIB(rt, clock_gettime, ALSA_LIBS="$ALSA_LIBS -lrt", alsa_found=no) AC_SUBST(ALSA_CFLAGS) AC_SUBST(ALSA_LIBS) ]) AC_DEFUN([AC_PATH_USB], [ PKG_CHECK_MODULES(USB, libusb, usb_found=yes, usb_found=no) AC_SUBST(USB_CFLAGS) AC_SUBST(USB_LIBS) AC_CHECK_LIB(usb, usb_get_busses, dummy=yes, AC_DEFINE(NEED_USB_GET_BUSSES, 1, [Define to 1 if you need the usb_get_busses() function.])) AC_CHECK_LIB(usb, usb_interrupt_read, dummy=yes, AC_DEFINE(NEED_USB_INTERRUPT_READ, 1, [Define to 1 if you need the usb_interrupt_read() function.])) ]) AC_DEFUN([AC_PATH_UDEV], [ PKG_CHECK_MODULES(UDEV, libudev, udev_found=yes, udev_found=no) AC_SUBST(UDEV_CFLAGS) AC_SUBST(UDEV_LIBS) ]) AC_DEFUN([AC_PATH_SNDFILE], [ PKG_CHECK_MODULES(SNDFILE, sndfile, sndfile_found=yes, sndfile_found=no) AC_SUBST(SNDFILE_CFLAGS) AC_SUBST(SNDFILE_LIBS) ]) AC_DEFUN([AC_PATH_READLINE], [ AC_CHECK_HEADER(readline/readline.h, AC_CHECK_LIB(readline, main, [ readline_found=yes AC_SUBST(READLINE_LIBS, "-lreadline") ], readline_found=no), []) ]) AC_DEFUN([AC_PATH_CHECK], [ PKG_CHECK_MODULES(CHECK, check >= 0.9.6, check_found=yes, check_found=no) AC_SUBST(CHECK_CFLAGS) AC_SUBST(CHECK_LIBS) ]) AC_DEFUN([AC_PATH_OUI], [ AC_ARG_WITH(ouifile, AS_HELP_STRING([--with-ouifile=PATH],[Path to the oui.txt file @<:@auto@:>@]), [ac_with_ouifile=$withval], [ac_with_ouifile="/var/lib/misc/oui.txt"]) AC_DEFINE_UNQUOTED(OUIFILE, ["$ac_with_ouifile"], [Define the OUI file path]) ]) AC_DEFUN([AC_ARG_BLUEZ], [ debug_enable=no optimization_enable=yes fortify_enable=yes pie_enable=yes sndfile_enable=${sndfile_found} hal_enable=no usb_enable=${usb_found} alsa_enable=${alsa_found} gstreamer_enable=${gstreamer_found} audio_enable=yes input_enable=yes serial_enable=yes network_enable=yes sap_enable=no service_enable=yes health_enable=no pnat_enable=no tools_enable=yes hidd_enable=no pand_enable=no dund_enable=no cups_enable=no test_enable=no bccmd_enable=no pcmcia_enable=no hid2hci_enable=no dfutool_enable=no datafiles_enable=yes telephony_driver=dummy maemo6_enable=no sap_driver=dummy dbusoob_enable=no wiimote_enable=no gatt_enable=no AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [ optimization_enable=${enableval} ]) AC_ARG_ENABLE(fortify, AC_HELP_STRING([--disable-fortify], [disable compile time buffer checks]), [ fortify_enable=${enableval} ]) AC_ARG_ENABLE(pie, AC_HELP_STRING([--disable-pie], [disable position independent executables flag]), [ pie_enable=${enableval} ]) AC_ARG_ENABLE(network, AC_HELP_STRING([--disable-network], [disable network plugin]), [ network_enable=${enableval} ]) AC_ARG_ENABLE(sap, AC_HELP_STRING([--enable-sap], [enable sap plugin]), [ sap_enable=${enableval} ]) AC_ARG_WITH(sap, AC_HELP_STRING([--with-sap=DRIVER], [select SAP driver]), [ sap_driver=${withval} ]) AC_SUBST([SAP_DRIVER], [sap-${sap_driver}.c]) AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [disable serial plugin]), [ serial_enable=${enableval} ]) AC_ARG_ENABLE(input, AC_HELP_STRING([--disable-input], [disable input plugin]), [ input_enable=${enableval} ]) AC_ARG_ENABLE(audio, AC_HELP_STRING([--disable-audio], [disable audio plugin]), [ audio_enable=${enableval} ]) AC_ARG_ENABLE(service, AC_HELP_STRING([--disable-service], [disable service plugin]), [ service_enable=${enableval} ]) AC_ARG_ENABLE(health, AC_HELP_STRING([--enable-health], [enable health plugin]), [ health_enable=${enableval} ]) AC_ARG_ENABLE(pnat, AC_HELP_STRING([--enable-pnat], [enable pnat plugin]), [ pnat_enable=${enableval} ]) AC_ARG_ENABLE(gstreamer, AC_HELP_STRING([--enable-gstreamer], [enable GStreamer support]), [ gstreamer_enable=${enableval} ]) AC_ARG_ENABLE(alsa, AC_HELP_STRING([--enable-alsa], [enable ALSA support]), [ alsa_enable=${enableval} ]) AC_ARG_ENABLE(usb, AC_HELP_STRING([--enable-usb], [enable USB support]), [ usb_enable=${enableval} ]) AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools], [install Bluetooth utilities]), [ tools_enable=${enableval} ]) AC_ARG_ENABLE(bccmd, AC_HELP_STRING([--enable-bccmd], [install BCCMD interface utility]), [ bccmd_enable=${enableval} ]) AC_ARG_ENABLE(pcmcia, AC_HELP_STRING([--enable-pcmcia], [install PCMCIA serial script]), [ pcmcia_enable=${enableval} ]) AC_ARG_ENABLE(hid2hci, AC_HELP_STRING([--enable-hid2hci], [install HID mode switching utility]), [ hid2hci_enable=${enableval} ]) AC_ARG_ENABLE(dfutool, AC_HELP_STRING([--enable-dfutool], [install DFU firmware upgrade utility]), [ dfutool_enable=${enableval} ]) AC_ARG_ENABLE(hidd, AC_HELP_STRING([--enable-hidd], [install HID daemon]), [ hidd_enable=${enableval} ]) AC_ARG_ENABLE(pand, AC_HELP_STRING([--enable-pand], [install PAN daemon]), [ pand_enable=${enableval} ]) AC_ARG_ENABLE(dund, AC_HELP_STRING([--enable-dund], [install DUN daemon]), [ dund_enable=${enableval} ]) AC_ARG_ENABLE(cups, AC_HELP_STRING([--enable-cups], [install CUPS backend support]), [ cups_enable=${enableval} ]) AC_ARG_ENABLE(test, AC_HELP_STRING([--enable-test], [install test programs]), [ test_enable=${enableval} ]) AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--enable-datafiles], [install Bluetooth configuration and data files]), [ datafiles_enable=${enableval} ]) AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable compiling with debugging information]), [ debug_enable=${enableval} ]) AC_ARG_WITH(telephony, AC_HELP_STRING([--with-telephony=DRIVER], [select telephony driver]), [ telephony_driver=${withval} ]) AC_SUBST([TELEPHONY_DRIVER], [telephony-${telephony_driver}.c]) AC_ARG_ENABLE(maemo6, AC_HELP_STRING([--enable-maemo6], [compile with maemo6 plugin]), [ maemo6_enable=${enableval} ]) AC_ARG_ENABLE(dbusoob, AC_HELP_STRING([--enable-dbusoob], [compile with D-Bus OOB plugin]), [ dbusoob_enable=${enableval} ]) AC_ARG_ENABLE(wiimote, AC_HELP_STRING([--enable-wiimote], [compile with Wii Remote plugin]), [ wiimote_enable=${enableval} ]) AC_ARG_ENABLE(hal, AC_HELP_STRING([--enable-hal], [Use HAL to determine adapter class]), [ hal_enable=${enableval} ]) AC_ARG_ENABLE(gatt, AC_HELP_STRING([--enable-gatt], [enable gatt module]), [ gatt_enable=${enableval} ]) misc_cflags="" misc_ldflags="" if (test "${fortify_enable}" = "yes"); then misc_cflags="$misc_cflags -D_FORTIFY_SOURCE=2" fi if (test "${pie_enable}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then misc_cflags="$misc_cflags -fPIC" misc_ldflags="$misc_ldflags -pie" fi if (test "${debug_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then misc_cflags="$misc_cflags -g" fi if (test "${optimization_enable}" = "no"); then misc_cflags="$misc_cflags -O0" fi AC_SUBST([MISC_CFLAGS], $misc_cflags) AC_SUBST([MISC_LDFLAGS], $misc_ldflags) if (test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"); then AC_DEFINE(HAVE_LIBUSB, 1, [Define to 1 if you have USB library.]) fi AM_CONDITIONAL(SNDFILE, test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes") AM_CONDITIONAL(USB, test "${usb_enable}" = "yes" && test "${usb_found}" = "yes") AM_CONDITIONAL(SBC, test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes" || test "${test_enable}" = "yes") AM_CONDITIONAL(ALSA, test "${alsa_enable}" = "yes" && test "${alsa_found}" = "yes") AM_CONDITIONAL(GSTREAMER, test "${gstreamer_enable}" = "yes" && test "${gstreamer_found}" = "yes") AM_CONDITIONAL(AUDIOPLUGIN, test "${audio_enable}" = "yes") AM_CONDITIONAL(INPUTPLUGIN, test "${input_enable}" = "yes") AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes") AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes") AM_CONDITIONAL(SAPPLUGIN, test "${sap_enable}" = "yes") AM_CONDITIONAL(SERVICEPLUGIN, test "${service_enable}" = "yes") AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes") AM_CONDITIONAL(MCAP, test "${health_enable}" = "yes") AM_CONDITIONAL(HAL, test "${hal_enable}" = "yes") AM_CONDITIONAL(READLINE, test "${readline_found}" = "yes") AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes") AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes") AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes") AM_CONDITIONAL(DUND, test "${dund_enable}" = "yes") AM_CONDITIONAL(CUPS, test "${cups_enable}" = "yes") AM_CONDITIONAL(TEST, test "${test_enable}" = "yes" && test "${check_found}" = "yes") AM_CONDITIONAL(TOOLS, test "${tools_enable}" = "yes") AM_CONDITIONAL(BCCMD, test "${bccmd_enable}" = "yes") AM_CONDITIONAL(PCMCIA, test "${pcmcia_enable}" = "yes") AM_CONDITIONAL(HID2HCI, test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes" && test "${udev_found}" = "yes") AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes") AM_CONDITIONAL(DATAFILES, test "${datafiles_enable}" = "yes") AM_CONDITIONAL(MAEMO6PLUGIN, test "${maemo6_enable}" = "yes") AM_CONDITIONAL(DBUSOOBPLUGIN, test "${dbusoob_enable}" = "yes") AM_CONDITIONAL(WIIMOTEPLUGIN, test "${wiimote_enable}" = "yes") AM_CONDITIONAL(GATTMODULES, test "${gatt_enable}" = "yes") ]) bluez-4.101/audio/0000755000000000000000000000000011771120005010702 500000000000000bluez-4.101/audio/unix.h0000644000000000000000000000207611376221745012001 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ void unix_device_removed(struct audio_device *dev); void unix_delay_report(struct audio_device *dev, uint8_t seid, uint16_t delay); int unix_init(void); void unix_exit(void); bluez-4.101/audio/unix.c0000644000000000000000000012550211766125764012003 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "ipc.h" #include "device.h" #include "manager.h" #include "avdtp.h" #include "media.h" #include "a2dp.h" #include "headset.h" #include "sink.h" #include "source.h" #include "gateway.h" #include "unix.h" #define check_nul(str) (str[sizeof(str) - 1] == '\0') typedef enum { TYPE_NONE, TYPE_HEADSET, TYPE_GATEWAY, TYPE_SINK, TYPE_SOURCE } service_type_t; typedef void (*notify_cb_t) (struct audio_device *dev, void *data); struct a2dp_data { struct avdtp *session; struct avdtp_stream *stream; struct a2dp_sep *sep; }; struct headset_data { gboolean locked; }; struct unix_client { struct audio_device *dev; GSList *caps; service_type_t type; char *interface; uint8_t seid; union { struct a2dp_data a2dp; struct headset_data hs; } d; int sock; int lock; int data_fd; /* To be deleted once two phase configuration is fully implemented */ unsigned int req_id; unsigned int cb_id; gboolean (*cancel) (struct audio_device *dev, unsigned int id); }; static GSList *clients = NULL; static int unix_sock = -1; static void client_free(void *data) { struct unix_client *client = data; DBG("client_free(%p)", client); if (client->cancel && client->dev && client->req_id > 0) client->cancel(client->dev, client->req_id); if (client->sock >= 0) close(client->sock); g_slist_free_full(client->caps, g_free); g_free(client->interface); g_free(client); } static int set_nonblocking(int fd) { long arg; arg = fcntl(fd, F_GETFL); if (arg < 0) return -errno; /* Return if already nonblocking */ if (arg & O_NONBLOCK) return 0; arg |= O_NONBLOCK; if (fcntl(fd, F_SETFL, arg) < 0) return -errno; return 0; } /* Pass file descriptor through local domain sockets (AF_LOCAL, formerly * AF_UNIX) and the sendmsg() system call with the cmsg_type field of a "struct * cmsghdr" set to SCM_RIGHTS and the data being an integer value equal to the * handle of the file descriptor to be passed. */ static int unix_sendmsg_fd(int sock, int fd) { char cmsg_b[CMSG_SPACE(sizeof(int))], m = 'm'; struct cmsghdr *cmsg; struct iovec iov = { &m, sizeof(m) }; struct msghdr msgh; memset(&msgh, 0, sizeof(msgh)); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_control = &cmsg_b; msgh.msg_controllen = CMSG_LEN(sizeof(int)); cmsg = CMSG_FIRSTHDR(&msgh); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int)); /* Initialize the payload */ memcpy(CMSG_DATA(cmsg), &fd, sizeof(int)); return sendmsg(sock, &msgh, MSG_NOSIGNAL); } static void unix_ipc_sendmsg(struct unix_client *client, const bt_audio_msg_header_t *msg) { const char *type = bt_audio_strtype(msg->type); const char *name = bt_audio_strname(msg->name); DBG("Audio API: %s -> %s", type, name); if (send(client->sock, msg, msg->length, 0) < 0) error("Error %s(%d)", strerror(errno), errno); } static void unix_ipc_error(struct unix_client *client, uint8_t name, int err) { char buf[BT_SUGGESTED_BUFFER_SIZE]; bt_audio_error_t *rsp = (void *) buf; if (!g_slist_find(clients, client)) return; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_ERROR; rsp->h.name = name; rsp->h.length = sizeof(*rsp); rsp->posix_errno = err; DBG("sending error %s(%d)", strerror(err), err); unix_ipc_sendmsg(client, &rsp->h); } static service_type_t select_service(struct audio_device *dev, const char *interface) { if (!interface) { if (dev->sink && avdtp_is_connected(&dev->src, &dev->dst)) return TYPE_SINK; else if (dev->source && avdtp_is_connected(&dev->src, &dev->dst)) return TYPE_SOURCE; else if (dev->headset && headset_is_active(dev)) return TYPE_HEADSET; else if (dev->sink) return TYPE_SINK; else if (dev->source) return TYPE_SOURCE; else if (dev->headset) return TYPE_HEADSET; } else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source) return TYPE_SOURCE; else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink) return TYPE_SINK; else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset) return TYPE_HEADSET; else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway) return TYPE_GATEWAY; return TYPE_NONE; } 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 unix_client *client = user_data; struct a2dp_data *a2dp = &client->d.a2dp; switch (new_state) { case AVDTP_STATE_IDLE: if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } if (a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } a2dp->stream = NULL; client->cb_id = 0; break; default: break; } } static uint8_t headset_generate_capability(struct audio_device *dev, codec_capabilities_t *codec) { pcm_capabilities_t *pcm; codec->seid = BT_A2DP_SEID_RANGE + 1; codec->transport = BT_CAPABILITIES_TRANSPORT_SCO; codec->type = BT_HFP_CODEC_PCM; codec->length = sizeof(*pcm); pcm = (void *) codec; pcm->sampling_rate = 8000; if (dev->headset) { if (headset_get_nrec(dev)) pcm->flags |= BT_PCM_FLAG_NREC; if (!headset_get_sco_hci(dev)) pcm->flags |= BT_PCM_FLAG_PCM_ROUTING; codec->configured = headset_is_active(dev); codec->lock = headset_get_lock(dev); } else { pcm->flags |= BT_PCM_FLAG_NREC; codec->configured = TRUE; codec->lock = 0; } return codec->length; } static void headset_discovery_complete(struct audio_device *dev, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_get_capabilities_rsp *rsp = (void *) buf; uint8_t length; client->req_id = 0; if (!dev) goto failed; memset(buf, 0, sizeof(buf)); length = headset_generate_capability(dev, (void *) rsp->data); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_GET_CAPABILITIES; rsp->h.length = sizeof(*rsp) + length; ba2str(&dev->src, rsp->source); ba2str(&dev->dst, rsp->destination); strncpy(rsp->object, dev->path, sizeof(rsp->object)); unix_ipc_sendmsg(client, &rsp->h); return; failed: error("discovery failed"); unix_ipc_error(client, BT_SET_CONFIGURATION, EIO); } static void headset_setup_complete(struct audio_device *dev, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_set_configuration_rsp *rsp = (void *) buf; client->req_id = 0; if (!dev) goto failed; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_SET_CONFIGURATION; rsp->h.length = sizeof(*rsp); rsp->link_mtu = 48; client->data_fd = headset_get_sco_fd(dev); unix_ipc_sendmsg(client, &rsp->h); return; failed: error("config failed"); unix_ipc_error(client, BT_SET_CONFIGURATION, EIO); } static void gateway_setup_complete(struct audio_device *dev, GError *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_set_configuration_rsp *rsp = (void *) buf; if (err) { unix_ipc_error(client, BT_SET_CONFIGURATION, err->code); return; } client->req_id = 0; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_SET_CONFIGURATION; rsp->h.length = sizeof(*rsp); rsp->link_mtu = 48; client->data_fd = gateway_get_sco_fd(dev); unix_ipc_sendmsg(client, &rsp->h); } static void headset_resume_complete(struct audio_device *dev, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_start_stream_rsp *rsp = (void *) buf; struct bt_new_stream_ind *ind = (void *) buf; client->req_id = 0; if (!dev) goto failed; client->data_fd = headset_get_sco_fd(dev); if (client->data_fd < 0) { error("Unable to get a SCO fd"); goto failed; } memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_START_STREAM; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); memset(buf, 0, sizeof(buf)); ind->h.type = BT_INDICATION; ind->h.name = BT_NEW_STREAM; ind->h.length = sizeof(*ind); unix_ipc_sendmsg(client, &ind->h); if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) { error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno); goto failed; } return; failed: error("headset_resume_complete: resume failed"); unix_ipc_error(client, BT_START_STREAM, EIO); } static void gateway_resume_complete(struct audio_device *dev, GError *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_start_stream_rsp *rsp = (void *) buf; struct bt_new_stream_ind *ind = (void *) buf; if (err) { unix_ipc_error(client, BT_START_STREAM, err->code); return; } memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_START_STREAM; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); memset(buf, 0, sizeof(buf)); ind->h.type = BT_INDICATION; ind->h.name = BT_NEW_STREAM; ind->h.length = sizeof(*ind); unix_ipc_sendmsg(client, &ind->h); client->data_fd = gateway_get_sco_fd(dev); if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) { error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno); unix_ipc_error(client, BT_START_STREAM, EIO); } client->req_id = 0; } static void headset_suspend_complete(struct audio_device *dev, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_stop_stream_rsp *rsp = (void *) buf; if (!dev) goto failed; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_STOP_STREAM; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); return; failed: error("suspend failed"); unix_ipc_error(client, BT_STOP_STREAM, EIO); } static void print_mpeg12(struct mpeg_codec_cap *mpeg) { DBG("Media Codec: MPEG12" " Channel Modes: %s%s%s%s" " Frequencies: %s%s%s%s%s%s" " Layers: %s%s%s" " CRC: %s", mpeg->channel_mode & MPEG_CHANNEL_MODE_MONO ? "Mono " : "", mpeg->channel_mode & MPEG_CHANNEL_MODE_DUAL_CHANNEL ? "DualChannel " : "", mpeg->channel_mode & MPEG_CHANNEL_MODE_STEREO ? "Stereo " : "", mpeg->channel_mode & MPEG_CHANNEL_MODE_JOINT_STEREO ? "JointStereo " : "", mpeg->frequency & MPEG_SAMPLING_FREQ_16000 ? "16Khz " : "", mpeg->frequency & MPEG_SAMPLING_FREQ_22050 ? "22.05Khz " : "", mpeg->frequency & MPEG_SAMPLING_FREQ_24000 ? "24Khz " : "", mpeg->frequency & MPEG_SAMPLING_FREQ_32000 ? "32Khz " : "", mpeg->frequency & MPEG_SAMPLING_FREQ_44100 ? "44.1Khz " : "", mpeg->frequency & MPEG_SAMPLING_FREQ_48000 ? "48Khz " : "", mpeg->layer & MPEG_LAYER_MP1 ? "1 " : "", mpeg->layer & MPEG_LAYER_MP2 ? "2 " : "", mpeg->layer & MPEG_LAYER_MP3 ? "3 " : "", mpeg->crc ? "Yes" : "No"); } static void print_sbc(struct sbc_codec_cap *sbc) { DBG("Media Codec: SBC" " Channel Modes: %s%s%s%s" " Frequencies: %s%s%s%s" " Subbands: %s%s" " Blocks: %s%s%s%s" " Bitpool: %d-%d", sbc->channel_mode & SBC_CHANNEL_MODE_MONO ? "Mono " : "", sbc->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL ? "DualChannel " : "", sbc->channel_mode & SBC_CHANNEL_MODE_STEREO ? "Stereo " : "", sbc->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO ? "JointStereo" : "", sbc->frequency & SBC_SAMPLING_FREQ_16000 ? "16Khz " : "", sbc->frequency & SBC_SAMPLING_FREQ_32000 ? "32Khz " : "", sbc->frequency & SBC_SAMPLING_FREQ_44100 ? "44.1Khz " : "", sbc->frequency & SBC_SAMPLING_FREQ_48000 ? "48Khz " : "", sbc->subbands & SBC_SUBBANDS_4 ? "4 " : "", sbc->subbands & SBC_SUBBANDS_8 ? "8 " : "", sbc->block_length & SBC_BLOCK_LENGTH_4 ? "4 " : "", sbc->block_length & SBC_BLOCK_LENGTH_8 ? "8 " : "", sbc->block_length & SBC_BLOCK_LENGTH_12 ? "12 " : "", sbc->block_length & SBC_BLOCK_LENGTH_16 ? "16 " : "", sbc->min_bitpool, sbc->max_bitpool); } static int a2dp_append_codec(struct bt_get_capabilities_rsp *rsp, struct avdtp_service_capability *cap, uint8_t seid, uint8_t type, uint8_t configured, uint8_t lock) { struct avdtp_media_codec_capability *codec_cap = (void *) cap->data; codec_capabilities_t *codec = (void *) rsp + rsp->h.length; size_t space_left; if (rsp->h.length > BT_SUGGESTED_BUFFER_SIZE) return -ENOMEM; space_left = BT_SUGGESTED_BUFFER_SIZE - rsp->h.length; /* endianness prevents direct cast */ if (codec_cap->media_codec_type == A2DP_CODEC_SBC) { struct sbc_codec_cap *sbc_cap = (void *) codec_cap; sbc_capabilities_t *sbc = (void *) codec; if (space_left < sizeof(sbc_capabilities_t)) return -ENOMEM; if (type == AVDTP_SEP_TYPE_SINK) codec->type = BT_A2DP_SBC_SINK; else if (type == AVDTP_SEP_TYPE_SOURCE) codec->type = BT_A2DP_SBC_SOURCE; else return -EINVAL; codec->length = sizeof(sbc_capabilities_t); sbc->channel_mode = sbc_cap->channel_mode; sbc->frequency = sbc_cap->frequency; sbc->allocation_method = sbc_cap->allocation_method; sbc->subbands = sbc_cap->subbands; sbc->block_length = sbc_cap->block_length; sbc->min_bitpool = sbc_cap->min_bitpool; sbc->max_bitpool = sbc_cap->max_bitpool; print_sbc(sbc_cap); } else if (codec_cap->media_codec_type == A2DP_CODEC_MPEG12) { struct mpeg_codec_cap *mpeg_cap = (void *) codec_cap; mpeg_capabilities_t *mpeg = (void *) codec; if (space_left < sizeof(mpeg_capabilities_t)) return -ENOMEM; if (type == AVDTP_SEP_TYPE_SINK) codec->type = BT_A2DP_MPEG12_SINK; else if (type == AVDTP_SEP_TYPE_SOURCE) codec->type = BT_A2DP_MPEG12_SOURCE; else return -EINVAL; codec->length = sizeof(mpeg_capabilities_t); mpeg->channel_mode = mpeg_cap->channel_mode; mpeg->crc = mpeg_cap->crc; mpeg->layer = mpeg_cap->layer; mpeg->frequency = mpeg_cap->frequency; mpeg->mpf = mpeg_cap->mpf; mpeg->bitrate = mpeg_cap->bitrate; print_mpeg12(mpeg_cap); } else { size_t codec_length, type_length, total_length; codec_length = cap->length - (sizeof(struct avdtp_service_capability) + sizeof(struct avdtp_media_codec_capability)); type_length = sizeof(codec_cap->media_codec_type); total_length = type_length + codec_length + sizeof(codec_capabilities_t); if (space_left < total_length) return -ENOMEM; if (type == AVDTP_SEP_TYPE_SINK) codec->type = BT_A2DP_UNKNOWN_SINK; else if (type == AVDTP_SEP_TYPE_SOURCE) codec->type = BT_A2DP_UNKNOWN_SOURCE; else return -EINVAL; codec->length = total_length; memcpy(codec->data, &codec_cap->media_codec_type, type_length); memcpy(codec->data + type_length, codec_cap->data, codec_length); } codec->seid = seid; codec->configured = configured; codec->lock = lock; rsp->h.length += codec->length; DBG("Append %s seid %d - length %d - total %d", configured ? "configured" : "", seid, codec->length, rsp->h.length); return 0; } static void a2dp_discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_get_capabilities_rsp *rsp = (void *) buf; struct a2dp_data *a2dp = &client->d.a2dp; if (!g_slist_find(clients, client)) { DBG("Client disconnected during discovery"); return; } if (err) goto failed; memset(buf, 0, sizeof(buf)); client->req_id = 0; rsp->h.type = BT_RESPONSE; rsp->h.name = BT_GET_CAPABILITIES; rsp->h.length = sizeof(*rsp); ba2str(&client->dev->src, rsp->source); ba2str(&client->dev->dst, rsp->destination); strncpy(rsp->object, client->dev->path, sizeof(rsp->object)); for (; seps; seps = g_slist_next(seps)) { struct avdtp_remote_sep *rsep = seps->data; struct a2dp_sep *sep; struct avdtp_service_capability *cap; struct avdtp_stream *stream; uint8_t type, seid, configured = 0, lock = 0; GSList *cl; type = avdtp_get_type(rsep); if (type != AVDTP_SEP_TYPE_SINK && type != AVDTP_SEP_TYPE_SOURCE) continue; cap = avdtp_get_codec(rsep); if (cap->category != AVDTP_MEDIA_CODEC) continue; seid = avdtp_get_seid(rsep); if (client->seid != 0 && client->seid != seid) continue; stream = avdtp_get_stream(rsep); if (stream) { configured = 1; if (client->seid == seid) cap = avdtp_stream_get_codec(stream); } for (cl = clients; cl; cl = cl->next) { struct unix_client *c = cl->data; struct a2dp_data *ca2dp = &c->d.a2dp; if (ca2dp->session == session && c->seid == seid) { lock = c->lock; break; } } sep = a2dp_get_sep(session, stream); if (sep && a2dp_sep_get_lock(sep)) lock = BT_WRITE_LOCK; a2dp_append_codec(rsp, cap, seid, type, configured, lock); } unix_ipc_sendmsg(client, &rsp->h); return; failed: error("discovery failed"); unix_ipc_error(client, BT_GET_CAPABILITIES, EIO); if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } avdtp_unref(a2dp->session); a2dp->session = NULL; a2dp->stream = NULL; } static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_set_configuration_rsp *rsp = (void *) buf; struct a2dp_data *a2dp = &client->d.a2dp; uint16_t imtu, omtu; GSList *caps; client->req_id = 0; if (err) goto failed; memset(buf, 0, sizeof(buf)); if (!stream) goto failed; if (client->cb_id > 0) avdtp_stream_remove_cb(a2dp->session, a2dp->stream, client->cb_id); a2dp->sep = sep; a2dp->stream = stream; if (!avdtp_stream_get_transport(stream, &client->data_fd, &imtu, &omtu, &caps)) { error("Unable to get stream transport"); goto failed; } rsp->h.type = BT_RESPONSE; rsp->h.name = BT_SET_CONFIGURATION; rsp->h.length = sizeof(*rsp); /* FIXME: Use imtu when fd_opt is CFG_FD_OPT_READ */ rsp->link_mtu = omtu; unix_ipc_sendmsg(client, &rsp->h); client->cb_id = avdtp_stream_add_cb(session, stream, stream_state_changed, client); return; failed: error("config failed"); unix_ipc_error(client, BT_SET_CONFIGURATION, EIO); avdtp_unref(a2dp->session); a2dp->session = NULL; a2dp->stream = NULL; a2dp->sep = NULL; } static void a2dp_resume_complete(struct avdtp *session, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_start_stream_rsp *rsp = (void *) buf; struct bt_new_stream_ind *ind = (void *) buf; struct a2dp_data *a2dp = &client->d.a2dp; if (err) goto failed; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_START_STREAM; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); memset(buf, 0, sizeof(buf)); ind->h.type = BT_RESPONSE; ind->h.name = BT_NEW_STREAM; rsp->h.length = sizeof(*ind); unix_ipc_sendmsg(client, &ind->h); if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) { error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno); goto failed; } return; failed: error("resume failed"); unix_ipc_error(client, BT_START_STREAM, EIO); if (client->cb_id > 0) { avdtp_stream_remove_cb(a2dp->session, a2dp->stream, client->cb_id); client->cb_id = 0; } if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } avdtp_unref(a2dp->session); a2dp->session = NULL; a2dp->stream = NULL; } static void a2dp_suspend_complete(struct avdtp *session, struct avdtp_error *err, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_stop_stream_rsp *rsp = (void *) buf; if (err) goto failed; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_STOP_STREAM; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); return; failed: error("suspend failed"); unix_ipc_error(client, BT_STOP_STREAM, EIO); } static void start_discovery(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp; int err = 0; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->session) a2dp->session = avdtp_get(&dev->src, &dev->dst); if (!a2dp->session) { error("Unable to get a session"); goto failed; } err = avdtp_discover(a2dp->session, a2dp_discovery_complete, client); if (err) { if (a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } goto failed; } break; case TYPE_HEADSET: case TYPE_GATEWAY: headset_discovery_complete(dev, client); break; default: error("No known services for device"); goto failed; } client->dev = dev; return; failed: unix_ipc_error(client, BT_GET_CAPABILITIES, err ? : EIO); } static void open_complete(struct audio_device *dev, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_open_rsp *rsp = (void *) buf; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_OPEN; rsp->h.length = sizeof(*rsp); ba2str(&dev->src, rsp->source); ba2str(&dev->dst, rsp->destination); strncpy(rsp->object, dev->path, sizeof(rsp->object)); unix_ipc_sendmsg(client, &rsp->h); } static void start_open(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp; struct headset_data *hs; struct avdtp_remote_sep *rsep; gboolean unref_avdtp_on_fail = FALSE; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->session) { a2dp->session = avdtp_get(&dev->src, &dev->dst); unref_avdtp_on_fail = TRUE; } if (!a2dp->session) { error("Unable to get a session"); goto failed; } if (a2dp->sep) { error("Client already has an opened session"); goto failed; } rsep = avdtp_get_remote_sep(a2dp->session, client->seid); if (!rsep) { error("Invalid seid %d", client->seid); goto failed; } a2dp->sep = a2dp_get(a2dp->session, rsep); if (!a2dp->sep) { error("seid %d not available or locked", client->seid); goto failed; } if (!a2dp_sep_lock(a2dp->sep, a2dp->session)) { error("Unable to open seid %d", client->seid); a2dp->sep = NULL; goto failed; } break; case TYPE_HEADSET: hs = &client->d.hs; if (hs->locked) { error("Client already has an opened session"); goto failed; } hs->locked = headset_lock(dev, client->lock); if (!hs->locked) { error("Unable to open seid %d", client->seid); goto failed; } break; case TYPE_GATEWAY: break; default: error("No known services for device"); goto failed; } client->dev = dev; open_complete(dev, client); return; failed: if (unref_avdtp_on_fail && a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } unix_ipc_error(client, BT_OPEN, EINVAL); } static void start_config(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp; struct headset_data *hs; unsigned int id; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->session) a2dp->session = avdtp_get(&dev->src, &dev->dst); if (!a2dp->session) { error("Unable to get a session"); goto failed; } if (!a2dp->sep) { error("seid %d not opened", client->seid); goto failed; } id = a2dp_config(a2dp->session, a2dp->sep, a2dp_config_complete, client->caps, client); client->cancel = a2dp_cancel; break; case TYPE_HEADSET: hs = &client->d.hs; if (!hs->locked) { error("seid %d not opened", client->seid); goto failed; } id = headset_config_stream(dev, TRUE, headset_setup_complete, client); client->cancel = headset_cancel_stream; break; case TYPE_GATEWAY: id = gateway_config_stream(dev, gateway_setup_complete, client); client->cancel = gateway_cancel_stream; break; default: error("No known services for device"); goto failed; } if (id == 0) { error("config failed"); goto failed; } client->req_id = id; g_slist_free(client->caps); client->caps = NULL; return; failed: unix_ipc_error(client, BT_SET_CONFIGURATION, EIO); } static void start_resume(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp = NULL; struct headset_data *hs; unsigned int id; struct avdtp *session = NULL; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->sep) { error("seid not opened"); goto failed; } if (!a2dp->session) { session = avdtp_get(&dev->src, &dev->dst); if (!session) { error("Unable to get a session"); goto failed; } a2dp->session = session; } id = a2dp_resume(a2dp->session, a2dp->sep, a2dp_resume_complete, client); client->cancel = a2dp_cancel; break; case TYPE_HEADSET: hs = &client->d.hs; if (!hs->locked) { error("seid not opened"); goto failed; } id = headset_request_stream(dev, headset_resume_complete, client); client->cancel = headset_cancel_stream; break; case TYPE_GATEWAY: id = gateway_request_stream(dev, gateway_resume_complete, client); client->cancel = gateway_cancel_stream; break; default: error("No known services for device"); goto failed; } if (id == 0) { error("start_resume: resume failed"); goto failed; } client->req_id = id; return; failed: if (session) { avdtp_unref(session); a2dp->session = NULL; } unix_ipc_error(client, BT_START_STREAM, EIO); } static void start_suspend(struct audio_device *dev, struct unix_client *client) { struct a2dp_data *a2dp = NULL; struct headset_data *hs; unsigned int id; struct avdtp *session = NULL; switch (client->type) { case TYPE_SINK: case TYPE_SOURCE: a2dp = &client->d.a2dp; if (!a2dp->sep) { error("seid not opened"); goto failed; } if (!a2dp->session) { session = avdtp_get(&dev->src, &dev->dst); if (!session) { error("Unable to get a session"); goto failed; } a2dp->session = session; } if (!a2dp->sep) { error("Unable to get a sep"); goto failed; } id = a2dp_suspend(a2dp->session, a2dp->sep, a2dp_suspend_complete, client); client->cancel = a2dp_cancel; break; case TYPE_HEADSET: hs = &client->d.hs; if (!hs->locked) { error("seid not opened"); goto failed; } id = headset_suspend_stream(dev, headset_suspend_complete, client); client->cancel = headset_cancel_stream; break; case TYPE_GATEWAY: gateway_suspend_stream(dev); client->cancel = gateway_cancel_stream; headset_suspend_complete(dev, client); id = 1; break; default: error("No known services for device"); goto failed; } if (id == 0) { error("suspend failed"); goto failed; } return; failed: if (session) { avdtp_unref(session); a2dp->session = NULL; } unix_ipc_error(client, BT_STOP_STREAM, EIO); } static void close_complete(struct audio_device *dev, void *user_data) { struct unix_client *client = user_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_close_rsp *rsp = (void *) buf; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_CLOSE; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); return; } static void start_close(struct audio_device *dev, struct unix_client *client, gboolean reply) { struct a2dp_data *a2dp; struct headset_data *hs; if (!client->dev) goto failed; switch (client->type) { case TYPE_HEADSET: hs = &client->d.hs; if (client->dev && hs->locked) { headset_unlock(client->dev, client->lock); hs->locked = FALSE; } break; case TYPE_GATEWAY: break; case TYPE_SOURCE: case TYPE_SINK: a2dp = &client->d.a2dp; if (client->cb_id > 0) { avdtp_stream_remove_cb(a2dp->session, a2dp->stream, client->cb_id); client->cb_id = 0; } if (a2dp->sep) { a2dp_sep_unlock(a2dp->sep, a2dp->session); a2dp->sep = NULL; } if (a2dp->session) { avdtp_unref(a2dp->session); a2dp->session = NULL; } a2dp->stream = NULL; break; default: error("No known services for device"); goto failed; } if (!reply) return; close_complete(dev, client); client->dev = NULL; return; failed: if (reply) unix_ipc_error(client, BT_STOP_STREAM, EINVAL); } static void handle_getcapabilities_req(struct unix_client *client, struct bt_get_capabilities_req *req) { struct audio_device *dev; bdaddr_t src, dst; int err = EIO; const char *interface; if (!check_nul(req->source) || !check_nul(req->destination) || !check_nul(req->object)) { err = EINVAL; goto failed; } str2ba(req->source, &src); str2ba(req->destination, &dst); if (!manager_find_device(req->object, &src, &dst, NULL, FALSE)) goto failed; if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO) interface = AUDIO_HEADSET_INTERFACE; else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP) interface = AUDIO_SINK_INTERFACE; else interface = client->interface; dev = manager_find_device(req->object, &src, &dst, interface, TRUE); if (!dev && (req->flags & BT_FLAG_AUTOCONNECT)) dev = manager_find_device(req->object, &src, &dst, interface, FALSE); if (!dev) { if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO) interface = AUDIO_GATEWAY_INTERFACE; else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP) interface = AUDIO_SOURCE_INTERFACE; else interface = NULL; dev = manager_find_device(req->object, &src, &dst, interface, TRUE); if (!dev && (req->flags & BT_FLAG_AUTOCONNECT)) dev = manager_find_device(req->object, &src, &dst, interface, FALSE); } if (!dev) { error("Unable to find a matching device"); goto failed; } client->type = select_service(dev, interface); if (client->type == TYPE_NONE) { error("No matching service found"); goto failed; } if (g_strcmp0(interface, client->interface) != 0) { g_free(client->interface); client->interface = g_strdup(interface); } client->seid = req->seid; start_discovery(dev, client); return; failed: unix_ipc_error(client, BT_GET_CAPABILITIES, err); } static int handle_sco_open(struct unix_client *client, struct bt_open_req *req) { if (!client->interface) client->interface = g_strdup(AUDIO_HEADSET_INTERFACE); else if (!g_str_equal(client->interface, AUDIO_HEADSET_INTERFACE) && !g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE)) return -EIO; DBG("open sco - object=%s source=%s destination=%s lock=%s%s", strcmp(req->object, "") ? req->object : "ANY", strcmp(req->source, "") ? req->source : "ANY", strcmp(req->destination, "") ? req->destination : "ANY", req->lock & BT_READ_LOCK ? "read" : "", req->lock & BT_WRITE_LOCK ? "write" : ""); return 0; } static int handle_a2dp_open(struct unix_client *client, struct bt_open_req *req) { if (!client->interface) /* FIXME: are we treating a sink or a source? */ client->interface = g_strdup(AUDIO_SINK_INTERFACE); else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE) && !g_str_equal(client->interface, AUDIO_SOURCE_INTERFACE)) return -EIO; DBG("open a2dp - object=%s source=%s destination=%s lock=%s%s", strcmp(req->object, "") ? req->object : "ANY", strcmp(req->source, "") ? req->source : "ANY", strcmp(req->destination, "") ? req->destination : "ANY", req->lock & BT_READ_LOCK ? "read" : "", req->lock & BT_WRITE_LOCK ? "write" : ""); return 0; } static void handle_open_req(struct unix_client *client, struct bt_open_req *req) { struct audio_device *dev; bdaddr_t src, dst; int err = 0; if (!check_nul(req->source) || !check_nul(req->destination) || !check_nul(req->object)) { err = EINVAL; goto failed; } str2ba(req->source, &src); str2ba(req->destination, &dst); if (req->seid > BT_A2DP_SEID_RANGE) { err = handle_sco_open(client, req); if (err < 0) { err = -err; goto failed; } } else { err = handle_a2dp_open(client, req); if (err < 0) { err = -err; goto failed; } } if (!manager_find_device(req->object, &src, &dst, NULL, FALSE)) goto failed; dev = manager_find_device(req->object, &src, &dst, client->interface, TRUE); if (!dev) dev = manager_find_device(req->object, &src, &dst, client->interface, FALSE); if (!dev) goto failed; client->seid = req->seid; client->lock = req->lock; start_open(dev, client); return; failed: unix_ipc_error(client, BT_OPEN, err ? : EIO); } static int handle_sco_transport(struct unix_client *client, struct bt_set_configuration_req *req) { struct audio_device *dev = client->dev; if (!client->interface) { if (dev->headset) client->interface = g_strdup(AUDIO_HEADSET_INTERFACE); else if (dev->gateway) client->interface = g_strdup(AUDIO_GATEWAY_INTERFACE); else return -EIO; } else if (!g_str_equal(client->interface, AUDIO_HEADSET_INTERFACE) && !g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE)) return -EIO; return 0; } static int handle_a2dp_transport(struct unix_client *client, struct bt_set_configuration_req *req) { struct avdtp_service_capability *media_transport, *media_codec; struct sbc_codec_cap sbc_cap; struct mpeg_codec_cap mpeg_cap; if (!client->interface) /* FIXME: are we treating a sink or a source? */ client->interface = g_strdup(AUDIO_SINK_INTERFACE); else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE) && !g_str_equal(client->interface, AUDIO_SOURCE_INTERFACE)) return -EIO; g_slist_free_full(client->caps, g_free); client->caps = NULL; media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0); client->caps = g_slist_append(client->caps, media_transport); if (req->codec.type == BT_A2DP_MPEG12_SINK || req->codec.type == BT_A2DP_MPEG12_SOURCE) { mpeg_capabilities_t *mpeg = (void *) &req->codec; memset(&mpeg_cap, 0, sizeof(mpeg_cap)); mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO; mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12; mpeg_cap.channel_mode = mpeg->channel_mode; mpeg_cap.crc = mpeg->crc; mpeg_cap.layer = mpeg->layer; mpeg_cap.frequency = mpeg->frequency; mpeg_cap.mpf = mpeg->mpf; mpeg_cap.bitrate = mpeg->bitrate; media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap, sizeof(mpeg_cap)); print_mpeg12(&mpeg_cap); } else if (req->codec.type == BT_A2DP_SBC_SINK || req->codec.type == BT_A2DP_SBC_SOURCE) { sbc_capabilities_t *sbc = (void *) &req->codec; memset(&sbc_cap, 0, sizeof(sbc_cap)); sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO; sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC; sbc_cap.channel_mode = sbc->channel_mode; sbc_cap.frequency = sbc->frequency; sbc_cap.allocation_method = sbc->allocation_method; sbc_cap.subbands = sbc->subbands; sbc_cap.block_length = sbc->block_length; sbc_cap.min_bitpool = sbc->min_bitpool; sbc_cap.max_bitpool = sbc->max_bitpool; media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap, sizeof(sbc_cap)); print_sbc(&sbc_cap); } else return -EINVAL; client->caps = g_slist_append(client->caps, media_codec); return 0; } static void handle_setconfiguration_req(struct unix_client *client, struct bt_set_configuration_req *req) { int err = 0; if (req->codec.seid != client->seid) { error("Unable to set configuration: seid %d not opened", req->codec.seid); goto failed; } if (!client->dev) goto failed; if (req->codec.transport == BT_CAPABILITIES_TRANSPORT_SCO) { err = handle_sco_transport(client, req); if (err < 0) { err = -err; goto failed; } } else if (req->codec.transport == BT_CAPABILITIES_TRANSPORT_A2DP) { err = handle_a2dp_transport(client, req); if (err < 0) { err = -err; goto failed; } } start_config(client->dev, client); return; failed: unix_ipc_error(client, BT_SET_CONFIGURATION, err ? : EIO); } static void handle_streamstart_req(struct unix_client *client, struct bt_start_stream_req *req) { if (!client->dev) goto failed; start_resume(client->dev, client); return; failed: unix_ipc_error(client, BT_START_STREAM, EIO); } static void handle_streamstop_req(struct unix_client *client, struct bt_stop_stream_req *req) { if (!client->dev) goto failed; start_suspend(client->dev, client); return; failed: unix_ipc_error(client, BT_STOP_STREAM, EIO); } static void handle_close_req(struct unix_client *client, struct bt_close_req *req) { if (!client->dev) goto failed; start_close(client->dev, client, TRUE); return; failed: unix_ipc_error(client, BT_CLOSE, EIO); } static void handle_control_req(struct unix_client *client, struct bt_control_req *req) { /* FIXME: really implement that */ char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_set_configuration_rsp *rsp = (void *) buf; memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_CONTROL; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); } static void handle_delay_report_req(struct unix_client *client, struct bt_delay_report_req *req) { char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_set_configuration_rsp *rsp = (void *) buf; struct a2dp_data *a2dp; int err; if (!client->dev) { err = -ENODEV; goto failed; } switch (client->type) { case TYPE_HEADSET: case TYPE_GATEWAY: err = -EINVAL; goto failed; case TYPE_SOURCE: case TYPE_SINK: a2dp = &client->d.a2dp; if (a2dp->session && a2dp->stream) { err = avdtp_delay_report(a2dp->session, a2dp->stream, req->delay); if (err < 0) goto failed; } else { err = -EINVAL; goto failed; } break; default: error("No known services for device"); err = -EINVAL; goto failed; } memset(buf, 0, sizeof(buf)); rsp->h.type = BT_RESPONSE; rsp->h.name = BT_DELAY_REPORT; rsp->h.length = sizeof(*rsp); unix_ipc_sendmsg(client, &rsp->h); return; failed: unix_ipc_error(client, BT_DELAY_REPORT, -err); } static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { char buf[BT_SUGGESTED_BUFFER_SIZE]; bt_audio_msg_header_t *msghdr = (void *) buf; struct unix_client *client = data; int len; const char *type, *name; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { DBG("Unix client disconnected (fd=%d)", client->sock); goto failed; } memset(buf, 0, sizeof(buf)); len = recv(client->sock, buf, sizeof(buf), 0); if (len < 0) { error("recv: %s (%d)", strerror(errno), errno); goto failed; } type = bt_audio_strtype(msghdr->type); name = bt_audio_strname(msghdr->name); DBG("Audio API: %s <- %s", type, name); if (msghdr->length != len) { error("Invalid message: length mismatch"); goto failed; } switch (msghdr->name) { case BT_GET_CAPABILITIES: handle_getcapabilities_req(client, (struct bt_get_capabilities_req *) msghdr); break; case BT_OPEN: handle_open_req(client, (struct bt_open_req *) msghdr); break; case BT_SET_CONFIGURATION: handle_setconfiguration_req(client, (struct bt_set_configuration_req *) msghdr); break; case BT_START_STREAM: handle_streamstart_req(client, (struct bt_start_stream_req *) msghdr); break; case BT_STOP_STREAM: handle_streamstop_req(client, (struct bt_stop_stream_req *) msghdr); break; case BT_CLOSE: handle_close_req(client, (struct bt_close_req *) msghdr); break; case BT_CONTROL: handle_control_req(client, (struct bt_control_req *) msghdr); break; case BT_DELAY_REPORT: handle_delay_report_req(client, (struct bt_delay_report_req *) msghdr); break; default: error("Audio API: received unexpected message name %d", msghdr->name); } return TRUE; failed: clients = g_slist_remove(clients, client); start_close(client->dev, client, FALSE); client_free(client); return FALSE; } static gboolean server_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct sockaddr_un addr; socklen_t addrlen; int sk, cli_sk; struct unix_client *client; GIOChannel *io; if (cond & G_IO_NVAL) return FALSE; if (cond & (G_IO_HUP | G_IO_ERR)) { g_io_channel_shutdown(chan, TRUE, NULL); return FALSE; } sk = g_io_channel_unix_get_fd(chan); memset(&addr, 0, sizeof(addr)); addrlen = sizeof(addr); cli_sk = accept(sk, (struct sockaddr *) &addr, &addrlen); if (cli_sk < 0) { error("accept: %s (%d)", strerror(errno), errno); return TRUE; } DBG("Accepted new client connection on unix socket (fd=%d)", cli_sk); set_nonblocking(cli_sk); client = g_new0(struct unix_client, 1); client->sock = cli_sk; clients = g_slist_append(clients, client); io = g_io_channel_unix_new(cli_sk); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, client_cb, client); g_io_channel_unref(io); return TRUE; } void unix_device_removed(struct audio_device *dev) { GSList *l; DBG("unix_device_removed(%p)", dev); l = clients; while (l) { struct unix_client *client = l->data; l = l->next; if (client->dev == dev) { clients = g_slist_remove(clients, client); start_close(client->dev, client, FALSE); client_free(client); } } } void unix_delay_report(struct audio_device *dev, uint8_t seid, uint16_t delay) { GSList *l; struct bt_delay_report_ind ind; DBG("unix_delay_report(%p): %u.%ums", dev, delay / 10, delay % 10); memset(&ind, 0, sizeof(ind)); ind.h.type = BT_INDICATION; ind.h.name = BT_DELAY_REPORT; ind.h.length = sizeof(ind); ind.delay = delay; for (l = clients; l != NULL; l = g_slist_next(l)) { struct unix_client *client = l->data; if (client->dev != dev || client->seid != seid) continue; unix_ipc_sendmsg(client, (void *) &ind); } } int unix_init(void) { GIOChannel *io; struct sockaddr_un addr = { AF_UNIX, BT_IPC_SOCKET_NAME }; int sk, err; sk = socket(PF_LOCAL, SOCK_STREAM, 0); if (sk < 0) { err = -errno; error("Can't create unix socket: %s (%d)", strerror(-err), -err); return err; } if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { err = -errno; error("Can't bind unix socket: %s (%d)", strerror(-err), -err); close(sk); return err; } set_nonblocking(sk); if (listen(sk, 1) < 0) { err = -errno; error("Can't listen on unix socket: %s (%d)", strerror(-err), -err); close(sk); return err; } unix_sock = sk; io = g_io_channel_unix_new(sk); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, server_cb, NULL); g_io_channel_unref(io); DBG("Unix socket created: %d", sk); return 0; } void unix_exit(void) { g_slist_free_full(clients, client_free); if (unix_sock >= 0) { close(unix_sock); unix_sock = -1; } } bluez-4.101/audio/gsta2dpsink.h0000644000000000000000000000442711766125764013260 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __GST_A2DP_SINK_H__ #define __GST_A2DP_SINK_H__ #include #include #include "gstavdtpsink.h" G_BEGIN_DECLS #define GST_TYPE_A2DP_SINK \ (gst_a2dp_sink_get_type()) #define GST_A2DP_SINK(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_A2DP_SINK,GstA2dpSink)) #define GST_A2DP_SINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_A2DP_SINK,GstA2dpSinkClass)) #define GST_IS_A2DP_SINK(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_A2DP_SINK)) #define GST_IS_A2DP_SINK_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_A2DP_SINK)) typedef struct _GstA2dpSink GstA2dpSink; typedef struct _GstA2dpSinkClass GstA2dpSinkClass; struct _GstA2dpSink { GstBin bin; GstBaseRTPPayload *rtp; GstAvdtpSink *sink; GstElement *capsfilter; GstElement *fakesink; gchar *device; gchar *transport; gboolean autoconnect; gboolean sink_is_in_bin; GstGhostPad *ghostpad; GstPadSetCapsFunction ghostpad_setcapsfunc; GstPadEventFunction ghostpad_eventfunc; GstEvent *newseg_event; /* Store the tags received before the a2dpsender sink is created * when it is created we forward this to it */ GstTagList *taglist; GMutex *cb_mutex; }; struct _GstA2dpSinkClass { GstBinClass parent_class; }; GType gst_a2dp_sink_get_type(void); gboolean gst_a2dp_sink_plugin_init (GstPlugin * plugin); GstCaps *gst_a2dp_sink_get_device_caps(GstA2dpSink *self); G_END_DECLS #endif bluez-4.101/audio/gstsbcutil.h0000644000000000000000000000465511766125764013215 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "sbc.h" #include #define SBC_AM_AUTO 0x02 #define SBC_MODE_AUTO 0x04 gint gst_sbc_select_rate_from_list(const GValue *value); gint gst_sbc_select_channels_from_range(const GValue *value); gint gst_sbc_select_blocks_from_list(const GValue *value); gint gst_sbc_select_subbands_from_list(const GValue *value); gint gst_sbc_select_bitpool_from_range(const GValue *value); const gchar *gst_sbc_get_allocation_from_list(const GValue *value); const gchar *gst_sbc_get_mode_from_list(const GValue *value, gint channels); gint gst_sbc_get_channel_number(gint mode); gint gst_sbc_parse_rate_from_sbc(gint frequency); gint gst_sbc_parse_rate_to_sbc(gint rate); gint gst_sbc_parse_subbands_from_sbc(gint subbands); gint gst_sbc_parse_subbands_to_sbc(gint subbands); gint gst_sbc_parse_blocks_from_sbc(gint blocks); gint gst_sbc_parse_blocks_to_sbc(gint blocks); const gchar *gst_sbc_parse_mode_from_sbc(gint mode); gint gst_sbc_parse_mode_to_sbc(const gchar *mode); const gchar *gst_sbc_parse_allocation_from_sbc(gint alloc); gint gst_sbc_parse_allocation_to_sbc(const gchar *allocation); GstCaps* gst_sbc_parse_caps_from_sbc(sbc_t *sbc); GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message); void gst_sbc_util_set_structure_int_param(GstStructure *structure, const gchar* field, gint field_value, GValue *value); void gst_sbc_util_set_structure_string_param(GstStructure *structure, const gchar* field, const gchar* field_value, GValue *value); gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps); bluez-4.101/audio/media.c0000644000000000000000000012753411766125764012106 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2009 Marcel Holtmann * Copyright (C) 2011 BMW Car IT GmbH. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "../src/adapter.h" #include "../src/dbus-common.h" #include "glib-helper.h" #include "log.h" #include "error.h" #include "device.h" #include "avdtp.h" #include "media.h" #include "transport.h" #include "a2dp.h" #include "avrcp.h" #include "headset.h" #include "gateway.h" #include "manager.h" #define MEDIA_INTERFACE "org.bluez.Media" #define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint" #define MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer" #define REQUEST_TIMEOUT (3 * 1000) /* 3 seconds */ struct media_adapter { bdaddr_t src; /* Adapter address */ char *path; /* Adapter path */ DBusConnection *conn; /* Adapter connection */ GSList *endpoints; /* Endpoints list */ GSList *players; /* Players list */ }; struct endpoint_request { struct media_endpoint *endpoint; DBusMessage *msg; DBusPendingCall *call; media_endpoint_cb_t cb; GDestroyNotify destroy; void *user_data; }; struct media_endpoint { struct a2dp_sep *sep; char *sender; /* Endpoint DBus bus id */ char *path; /* Endpoint object path */ char *uuid; /* Endpoint property UUID */ uint8_t codec; /* Endpoint codec */ uint8_t *capabilities; /* Endpoint property capabilities */ size_t size; /* Endpoint capabilities size */ guint hs_watch; guint ag_watch; guint watch; GSList *requests; struct media_adapter *adapter; GSList *transports; }; struct media_player { struct media_adapter *adapter; struct avrcp_player *player; char *sender; /* Player DBus bus id */ char *path; /* Player object path */ GHashTable *settings; /* Player settings */ GHashTable *track; /* Player current track */ guint watch; guint property_watch; guint track_watch; uint8_t status; uint32_t position; uint8_t volume; GTimer *timer; }; struct metadata_value { int type; union { char *str; uint32_t num; } value; }; static GSList *adapters = NULL; static void endpoint_request_free(struct endpoint_request *request) { if (request->call) dbus_pending_call_unref(request->call); if (request->destroy) request->destroy(request->user_data); dbus_message_unref(request->msg); g_free(request); } static void media_endpoint_cancel(struct endpoint_request *request) { struct media_endpoint *endpoint = request->endpoint; if (request->call) dbus_pending_call_cancel(request->call); endpoint->requests = g_slist_remove(endpoint->requests, request); endpoint_request_free(request); } static void media_endpoint_cancel_all(struct media_endpoint *endpoint) { while (endpoint->requests != NULL) media_endpoint_cancel(endpoint->requests->data); } static void media_endpoint_destroy(struct media_endpoint *endpoint) { struct media_adapter *adapter = endpoint->adapter; DBG("sender=%s path=%s", endpoint->sender, endpoint->path); if (endpoint->hs_watch) headset_remove_state_cb(endpoint->hs_watch); if (endpoint->ag_watch) gateway_remove_state_cb(endpoint->ag_watch); media_endpoint_cancel_all(endpoint); g_slist_free_full(endpoint->transports, (GDestroyNotify) media_transport_destroy); g_dbus_remove_watch(adapter->conn, endpoint->watch); g_free(endpoint->capabilities); g_free(endpoint->sender); g_free(endpoint->path); g_free(endpoint->uuid); g_free(endpoint); } static void media_endpoint_remove(struct media_endpoint *endpoint) { struct media_adapter *adapter = endpoint->adapter; if (endpoint->sep) { a2dp_remove_sep(endpoint->sep); return; } info("Endpoint unregistered: sender=%s path=%s", endpoint->sender, endpoint->path); adapter->endpoints = g_slist_remove(adapter->endpoints, endpoint); media_endpoint_destroy(endpoint); } static void media_endpoint_exit(DBusConnection *connection, void *user_data) { struct media_endpoint *endpoint = user_data; endpoint->watch = 0; media_endpoint_remove(endpoint); } static void headset_setconf_cb(struct media_endpoint *endpoint, void *ret, int size, void *user_data) { struct audio_device *dev = user_data; if (ret != NULL) return; headset_shutdown(dev); } static void clear_configuration(struct media_endpoint *endpoint, struct media_transport *transport) { DBusConnection *conn; DBusMessage *msg; const char *path; conn = endpoint->adapter->conn; msg = dbus_message_new_method_call(endpoint->sender, endpoint->path, MEDIA_ENDPOINT_INTERFACE, "ClearConfiguration"); if (msg == NULL) { error("Couldn't allocate D-Bus message"); goto done; } path = media_transport_get_path(transport); dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); g_dbus_send_message(conn, msg); done: endpoint->transports = g_slist_remove(endpoint->transports, transport); media_transport_destroy(transport); } static void clear_endpoint(struct media_endpoint *endpoint) { media_endpoint_cancel_all(endpoint); while (endpoint->transports != NULL) clear_configuration(endpoint, endpoint->transports->data); } static void endpoint_reply(DBusPendingCall *call, void *user_data) { struct endpoint_request *request = user_data; struct media_endpoint *endpoint = request->endpoint; DBusMessage *reply; DBusError err; gboolean value; void *ret = NULL; int size = -1; /* steal_reply will always return non-NULL since the callback * is only called after a reply has been received */ reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("Endpoint replied with an error: %s", err.name); /* Clear endpoint configuration in case of NO_REPLY error */ if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { if (request->cb) request->cb(endpoint, NULL, size, request->user_data); clear_endpoint(endpoint); dbus_message_unref(reply); dbus_error_free(&err); return; } dbus_error_free(&err); goto done; } if (dbus_message_is_method_call(request->msg, MEDIA_ENDPOINT_INTERFACE, "SelectConfiguration")) { DBusMessageIter args, array; uint8_t *configuration; dbus_message_iter_init(reply, &args); dbus_message_iter_recurse(&args, &array); dbus_message_iter_get_fixed_array(&array, &configuration, &size); ret = configuration; goto done; } else if (!dbus_message_get_args(reply, &err, DBUS_TYPE_INVALID)) { error("Wrong reply signature: %s", err.message); dbus_error_free(&err); goto done; } size = 1; value = TRUE; ret = &value; done: dbus_message_unref(reply); if (request->cb) request->cb(endpoint, ret, size, request->user_data); endpoint->requests = g_slist_remove(endpoint->requests, request); endpoint_request_free(request); } static gboolean media_endpoint_async_call(DBusConnection *conn, DBusMessage *msg, struct media_endpoint *endpoint, media_endpoint_cb_t cb, void *user_data, GDestroyNotify destroy) { struct endpoint_request *request; request = g_new0(struct endpoint_request, 1); /* Timeout should be less than avdtp request timeout (4 seconds) */ if (dbus_connection_send_with_reply(conn, msg, &request->call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); g_free(request); return FALSE; } dbus_pending_call_set_notify(request->call, endpoint_reply, request, NULL); request->endpoint = endpoint; request->msg = msg; request->cb = cb; request->destroy = destroy; request->user_data = user_data; endpoint->requests = g_slist_append(endpoint->requests, request); DBG("Calling %s: name = %s path = %s", dbus_message_get_member(msg), dbus_message_get_destination(msg), dbus_message_get_path(msg)); return TRUE; } static gboolean select_configuration(struct media_endpoint *endpoint, uint8_t *capabilities, size_t length, media_endpoint_cb_t cb, void *user_data, GDestroyNotify destroy) { DBusConnection *conn; DBusMessage *msg; conn = endpoint->adapter->conn; msg = dbus_message_new_method_call(endpoint->sender, endpoint->path, MEDIA_ENDPOINT_INTERFACE, "SelectConfiguration"); if (msg == NULL) { error("Couldn't allocate D-Bus message"); return FALSE; } dbus_message_append_args(msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &capabilities, length, DBUS_TYPE_INVALID); return media_endpoint_async_call(conn, msg, endpoint, cb, user_data, destroy); } static gint transport_device_cmp(gconstpointer data, gconstpointer user_data) { struct media_transport *transport = (struct media_transport *) data; const struct audio_device *device = user_data; if (device == media_transport_get_dev(transport)) return 0; return -1; } static struct media_transport *find_device_transport( struct media_endpoint *endpoint, struct audio_device *device) { GSList *match; match = g_slist_find_custom(endpoint->transports, device, transport_device_cmp); if (match == NULL) return NULL; return match->data; } static gboolean set_configuration(struct media_endpoint *endpoint, struct audio_device *device, uint8_t *configuration, size_t size, media_endpoint_cb_t cb, void *user_data, GDestroyNotify destroy) { DBusConnection *conn; DBusMessage *msg; const char *path; DBusMessageIter iter; struct media_transport *transport; transport = find_device_transport(endpoint, device); if (transport != NULL) return FALSE; conn = endpoint->adapter->conn; transport = media_transport_create(conn, endpoint, device, configuration, size); if (transport == NULL) return FALSE; msg = dbus_message_new_method_call(endpoint->sender, endpoint->path, MEDIA_ENDPOINT_INTERFACE, "SetConfiguration"); if (msg == NULL) { error("Couldn't allocate D-Bus message"); media_transport_destroy(transport); return FALSE; } endpoint->transports = g_slist_append(endpoint->transports, transport); dbus_message_iter_init_append(msg, &iter); path = media_transport_get_path(transport); dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path); transport_get_properties(transport, &iter); return media_endpoint_async_call(conn, msg, endpoint, cb, user_data, destroy); } static void release_endpoint(struct media_endpoint *endpoint) { DBusMessage *msg; DBG("sender=%s path=%s", endpoint->sender, endpoint->path); /* already exit */ if (endpoint->watch == 0) goto done; msg = dbus_message_new_method_call(endpoint->sender, endpoint->path, MEDIA_ENDPOINT_INTERFACE, "Release"); if (msg == NULL) { error("Couldn't allocate D-Bus message"); return; } g_dbus_send_message(endpoint->adapter->conn, msg); done: media_endpoint_remove(endpoint); } static void headset_state_changed(struct audio_device *dev, headset_state_t old_state, headset_state_t new_state, void *user_data) { struct media_endpoint *endpoint = user_data; struct media_transport *transport; DBG(""); if (bacmp(&endpoint->adapter->src, &dev->src) != 0) return; switch (new_state) { case HEADSET_STATE_DISCONNECTED: transport = find_device_transport(endpoint, dev); if (transport != NULL) { DBG("Clear endpoint %p", endpoint); clear_configuration(endpoint, transport); } break; case HEADSET_STATE_CONNECTING: set_configuration(endpoint, dev, NULL, 0, headset_setconf_cb, dev, NULL); break; case HEADSET_STATE_CONNECTED: break; case HEADSET_STATE_PLAY_IN_PROGRESS: break; case HEADSET_STATE_PLAYING: break; } } static const char *get_name(struct a2dp_sep *sep, void *user_data) { struct media_endpoint *endpoint = user_data; return endpoint->sender; } static size_t get_capabilities(struct a2dp_sep *sep, uint8_t **capabilities, void *user_data) { struct media_endpoint *endpoint = user_data; *capabilities = endpoint->capabilities; return endpoint->size; } struct a2dp_config_data { struct a2dp_setup *setup; a2dp_endpoint_config_t cb; }; struct a2dp_select_data { struct a2dp_setup *setup; a2dp_endpoint_select_t cb; }; static void select_cb(struct media_endpoint *endpoint, void *ret, int size, void *user_data) { struct a2dp_select_data *data = user_data; data->cb(data->setup, ret, size); } static int select_config(struct a2dp_sep *sep, uint8_t *capabilities, size_t length, struct a2dp_setup *setup, a2dp_endpoint_select_t cb, void *user_data) { struct media_endpoint *endpoint = user_data; struct a2dp_select_data *data; data = g_new0(struct a2dp_select_data, 1); data->setup = setup; data->cb = cb; if (select_configuration(endpoint, capabilities, length, select_cb, data, g_free) == TRUE) return 0; g_free(data); return -ENOMEM; } static void config_cb(struct media_endpoint *endpoint, void *ret, int size, void *user_data) { struct a2dp_config_data *data = user_data; data->cb(data->setup, ret ? TRUE : FALSE); } static int set_config(struct a2dp_sep *sep, struct audio_device *dev, uint8_t *configuration, size_t length, struct a2dp_setup *setup, a2dp_endpoint_config_t cb, void *user_data) { struct media_endpoint *endpoint = user_data; struct a2dp_config_data *data; data = g_new0(struct a2dp_config_data, 1); data->setup = setup; data->cb = cb; if (set_configuration(endpoint, dev, configuration, length, config_cb, data, g_free) == TRUE) return 0; g_free(data); return -ENOMEM; } static void clear_config(struct a2dp_sep *sep, void *user_data) { struct media_endpoint *endpoint = user_data; clear_endpoint(endpoint); } static void set_delay(struct a2dp_sep *sep, uint16_t delay, void *user_data) { struct media_endpoint *endpoint = user_data; if (endpoint->transports == NULL) return; media_transport_update_delay(endpoint->transports->data, delay); } static struct a2dp_endpoint a2dp_endpoint = { .get_name = get_name, .get_capabilities = get_capabilities, .select_configuration = select_config, .set_configuration = set_config, .clear_configuration = clear_config, .set_delay = set_delay }; static void a2dp_destroy_endpoint(void *user_data) { struct media_endpoint *endpoint = user_data; clear_endpoint(endpoint); endpoint->sep = NULL; release_endpoint(endpoint); } static void gateway_setconf_cb(struct media_endpoint *endpoint, void *ret, int size, void *user_data) { struct audio_device *dev = user_data; if (ret != NULL) return; gateway_set_state(dev, GATEWAY_STATE_DISCONNECTED); } static void gateway_state_changed(struct audio_device *dev, gateway_state_t old_state, gateway_state_t new_state, void *user_data) { struct media_endpoint *endpoint = user_data; struct media_transport *transport; DBG(""); if (bacmp(&endpoint->adapter->src, &dev->src) != 0) return; switch (new_state) { case GATEWAY_STATE_DISCONNECTED: transport = find_device_transport(endpoint, dev); if (transport != NULL) { DBG("Clear endpoint %p", endpoint); clear_configuration(endpoint, transport); } break; case GATEWAY_STATE_CONNECTING: set_configuration(endpoint, dev, NULL, 0, gateway_setconf_cb, dev, NULL); break; case GATEWAY_STATE_CONNECTED: break; case GATEWAY_STATE_PLAYING: break; } } static gboolean endpoint_init_a2dp_source(struct media_endpoint *endpoint, gboolean delay_reporting, int *err) { endpoint->sep = a2dp_add_sep(&endpoint->adapter->src, AVDTP_SEP_TYPE_SOURCE, endpoint->codec, delay_reporting, &a2dp_endpoint, endpoint, a2dp_destroy_endpoint, err); if (endpoint->sep == NULL) return FALSE; return TRUE; } static gboolean endpoint_init_a2dp_sink(struct media_endpoint *endpoint, gboolean delay_reporting, int *err) { endpoint->sep = a2dp_add_sep(&endpoint->adapter->src, AVDTP_SEP_TYPE_SINK, endpoint->codec, delay_reporting, &a2dp_endpoint, endpoint, a2dp_destroy_endpoint, err); if (endpoint->sep == NULL) return FALSE; return TRUE; } static gboolean endpoint_init_ag(struct media_endpoint *endpoint, int *err) { GSList *list; GSList *l; endpoint->hs_watch = headset_add_state_cb(headset_state_changed, endpoint); list = manager_find_devices(NULL, &endpoint->adapter->src, BDADDR_ANY, AUDIO_HEADSET_INTERFACE, TRUE); for (l = list; l != NULL; l = l->next) { struct audio_device *dev = l->data; set_configuration(endpoint, dev, NULL, 0, headset_setconf_cb, dev, NULL); } g_slist_free(list); return TRUE; } static gboolean endpoint_init_hs(struct media_endpoint *endpoint, int *err) { GSList *list; GSList *l; endpoint->ag_watch = gateway_add_state_cb(gateway_state_changed, endpoint); list = manager_find_devices(NULL, &endpoint->adapter->src, BDADDR_ANY, AUDIO_GATEWAY_INTERFACE, TRUE); for (l = list; l != NULL; l = l->next) { struct audio_device *dev = l->data; set_configuration(endpoint, dev, NULL, 0, gateway_setconf_cb, dev, NULL); } g_slist_free(list); return TRUE; } static struct media_endpoint *media_endpoint_create(struct media_adapter *adapter, const char *sender, const char *path, const char *uuid, gboolean delay_reporting, uint8_t codec, uint8_t *capabilities, int size, int *err) { struct media_endpoint *endpoint; gboolean succeeded; endpoint = g_new0(struct media_endpoint, 1); endpoint->sender = g_strdup(sender); endpoint->path = g_strdup(path); endpoint->uuid = g_strdup(uuid); endpoint->codec = codec; if (size > 0) { endpoint->capabilities = g_new(uint8_t, size); memcpy(endpoint->capabilities, capabilities, size); endpoint->size = size; } endpoint->adapter = adapter; if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0) succeeded = endpoint_init_a2dp_source(endpoint, delay_reporting, err); else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0) succeeded = endpoint_init_a2dp_sink(endpoint, delay_reporting, err); else if (strcasecmp(uuid, HFP_AG_UUID) == 0 || strcasecmp(uuid, HSP_AG_UUID) == 0) succeeded = endpoint_init_ag(endpoint, err); else if (strcasecmp(uuid, HFP_HS_UUID) == 0 || strcasecmp(uuid, HSP_HS_UUID) == 0) succeeded = endpoint_init_hs(endpoint, err); else { succeeded = FALSE; if (err) *err = -EINVAL; } if (!succeeded) { g_free(endpoint); return NULL; } endpoint->watch = g_dbus_add_disconnect_watch(adapter->conn, sender, media_endpoint_exit, endpoint, NULL); adapter->endpoints = g_slist_append(adapter->endpoints, endpoint); info("Endpoint registered: sender=%s path=%s", sender, path); if (err) *err = 0; return endpoint; } static struct media_endpoint *media_adapter_find_endpoint( struct media_adapter *adapter, const char *sender, const char *path, const char *uuid) { GSList *l; for (l = adapter->endpoints; l; l = l->next) { struct media_endpoint *endpoint = l->data; if (sender && g_strcmp0(endpoint->sender, sender) != 0) continue; if (path && g_strcmp0(endpoint->path, path) != 0) continue; if (uuid && g_strcmp0(endpoint->uuid, uuid) != 0) continue; return endpoint; } return NULL; } static int parse_properties(DBusMessageIter *props, const char **uuid, gboolean *delay_reporting, uint8_t *codec, uint8_t **capabilities, int *size) { gboolean has_uuid = FALSE; gboolean has_codec = FALSE; while (dbus_message_iter_get_arg_type(props) == DBUS_TYPE_DICT_ENTRY) { const char *key; DBusMessageIter value, entry; int var; dbus_message_iter_recurse(props, &entry); dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); dbus_message_iter_recurse(&entry, &value); var = dbus_message_iter_get_arg_type(&value); if (strcasecmp(key, "UUID") == 0) { if (var != DBUS_TYPE_STRING) return -EINVAL; dbus_message_iter_get_basic(&value, uuid); has_uuid = TRUE; } else if (strcasecmp(key, "Codec") == 0) { if (var != DBUS_TYPE_BYTE) return -EINVAL; dbus_message_iter_get_basic(&value, codec); has_codec = TRUE; } else if (strcasecmp(key, "DelayReporting") == 0) { if (var != DBUS_TYPE_BOOLEAN) return -EINVAL; dbus_message_iter_get_basic(&value, delay_reporting); } else if (strcasecmp(key, "Capabilities") == 0) { DBusMessageIter array; if (var != DBUS_TYPE_ARRAY) return -EINVAL; dbus_message_iter_recurse(&value, &array); dbus_message_iter_get_fixed_array(&array, capabilities, size); } dbus_message_iter_next(props); } return (has_uuid && has_codec) ? 0 : -EINVAL; } static DBusMessage *register_endpoint(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_adapter *adapter = data; DBusMessageIter args, props; const char *sender, *path, *uuid; gboolean delay_reporting = FALSE; uint8_t codec; uint8_t *capabilities; int size = 0; int err; sender = dbus_message_get_sender(msg); dbus_message_iter_init(msg, &args); dbus_message_iter_get_basic(&args, &path); dbus_message_iter_next(&args); if (media_adapter_find_endpoint(adapter, sender, path, NULL) != NULL) return btd_error_already_exists(msg); dbus_message_iter_recurse(&args, &props); if (dbus_message_iter_get_arg_type(&props) != DBUS_TYPE_DICT_ENTRY) return btd_error_invalid_args(msg); if (parse_properties(&props, &uuid, &delay_reporting, &codec, &capabilities, &size) < 0) return btd_error_invalid_args(msg); if (media_endpoint_create(adapter, sender, path, uuid, delay_reporting, codec, capabilities, size, &err) == NULL) { if (err == -EPROTONOSUPPORT) return btd_error_not_supported(msg); else return btd_error_invalid_args(msg); } return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static DBusMessage *unregister_endpoint(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_adapter *adapter = data; struct media_endpoint *endpoint; const char *sender, *path; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return NULL; sender = dbus_message_get_sender(msg); endpoint = media_adapter_find_endpoint(adapter, sender, path, NULL); if (endpoint == NULL) return btd_error_does_not_exist(msg); media_endpoint_remove(endpoint); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static struct media_player *media_adapter_find_player( struct media_adapter *adapter, const char *sender, const char *path) { GSList *l; for (l = adapter->players; l; l = l->next) { struct media_player *mp = l->data; if (sender && g_strcmp0(mp->sender, sender) != 0) continue; if (path && g_strcmp0(mp->path, path) != 0) continue; return mp; } return NULL; } static void release_player(struct media_player *mp) { DBusMessage *msg; DBG("sender=%s path=%s", mp->sender, mp->path); msg = dbus_message_new_method_call(mp->sender, mp->path, MEDIA_PLAYER_INTERFACE, "Release"); if (msg == NULL) { error("Couldn't allocate D-Bus message"); return; } g_dbus_send_message(mp->adapter->conn, msg); } static void media_player_free(gpointer data) { struct media_player *mp = data; struct media_adapter *adapter = mp->adapter; if (mp->player) { adapter->players = g_slist_remove(adapter->players, mp); release_player(mp); } g_dbus_remove_watch(adapter->conn, mp->watch); g_dbus_remove_watch(adapter->conn, mp->property_watch); g_dbus_remove_watch(adapter->conn, mp->track_watch); if (mp->track) g_hash_table_unref(mp->track); if (mp->settings) g_hash_table_unref(mp->settings); g_timer_destroy(mp->timer); g_free(mp->sender); g_free(mp->path); g_free(mp); } static void media_player_destroy(struct media_player *mp) { struct media_adapter *adapter = mp->adapter; DBG("sender=%s path=%s", mp->sender, mp->path); if (mp->player) { struct avrcp_player *player = mp->player; mp->player = NULL; adapter->players = g_slist_remove(adapter->players, mp); avrcp_unregister_player(player); return; } media_player_free(mp); } static void media_player_remove(struct media_player *mp) { info("Player unregistered: sender=%s path=%s", mp->sender, mp->path); media_player_destroy(mp); } static const char *attrval_to_str(uint8_t attr, uint8_t value) { switch (attr) { case AVRCP_ATTRIBUTE_EQUALIZER: switch (value) { case AVRCP_EQUALIZER_ON: return "on"; case AVRCP_EQUALIZER_OFF: return "off"; } break; case AVRCP_ATTRIBUTE_REPEAT_MODE: switch (value) { case AVRCP_REPEAT_MODE_OFF: return "off"; case AVRCP_REPEAT_MODE_SINGLE: return "singletrack"; case AVRCP_REPEAT_MODE_ALL: return "alltracks"; case AVRCP_REPEAT_MODE_GROUP: return "group"; } break; /* Shuffle and scan have the same values */ case AVRCP_ATTRIBUTE_SHUFFLE: case AVRCP_ATTRIBUTE_SCAN: switch (value) { case AVRCP_SCAN_OFF: return "off"; case AVRCP_SCAN_ALL: return "alltracks"; case AVRCP_SCAN_GROUP: return "group"; } break; } return NULL; } static int attrval_to_val(uint8_t attr, const char *value) { int ret; switch (attr) { case AVRCP_ATTRIBUTE_EQUALIZER: if (!strcmp(value, "off")) ret = AVRCP_EQUALIZER_OFF; else if (!strcmp(value, "on")) ret = AVRCP_EQUALIZER_ON; else ret = -EINVAL; return ret; case AVRCP_ATTRIBUTE_REPEAT_MODE: if (!strcmp(value, "off")) ret = AVRCP_REPEAT_MODE_OFF; else if (!strcmp(value, "singletrack")) ret = AVRCP_REPEAT_MODE_SINGLE; else if (!strcmp(value, "alltracks")) ret = AVRCP_REPEAT_MODE_ALL; else if (!strcmp(value, "group")) ret = AVRCP_REPEAT_MODE_GROUP; else ret = -EINVAL; return ret; case AVRCP_ATTRIBUTE_SHUFFLE: if (!strcmp(value, "off")) ret = AVRCP_SHUFFLE_OFF; else if (!strcmp(value, "alltracks")) ret = AVRCP_SHUFFLE_ALL; else if (!strcmp(value, "group")) ret = AVRCP_SHUFFLE_GROUP; else ret = -EINVAL; return ret; case AVRCP_ATTRIBUTE_SCAN: if (!strcmp(value, "off")) ret = AVRCP_SCAN_OFF; else if (!strcmp(value, "alltracks")) ret = AVRCP_SCAN_ALL; else if (!strcmp(value, "group")) ret = AVRCP_SCAN_GROUP; else ret = -EINVAL; return ret; } return -EINVAL; } static const char *attr_to_str(uint8_t attr) { switch (attr) { case AVRCP_ATTRIBUTE_EQUALIZER: return "Equalizer"; case AVRCP_ATTRIBUTE_REPEAT_MODE: return "Repeat"; case AVRCP_ATTRIBUTE_SHUFFLE: return "Shuffle"; case AVRCP_ATTRIBUTE_SCAN: return "Scan"; } return NULL; } static int attr_to_val(const char *str) { if (!strcasecmp(str, "Equalizer")) return AVRCP_ATTRIBUTE_EQUALIZER; else if (!strcasecmp(str, "Repeat")) return AVRCP_ATTRIBUTE_REPEAT_MODE; else if (!strcasecmp(str, "Shuffle")) return AVRCP_ATTRIBUTE_SHUFFLE; else if (!strcasecmp(str, "Scan")) return AVRCP_ATTRIBUTE_SCAN; return -EINVAL; } static int play_status_to_val(const char *status) { if (!strcasecmp(status, "stopped")) return AVRCP_PLAY_STATUS_STOPPED; else if (!strcasecmp(status, "playing")) return AVRCP_PLAY_STATUS_PLAYING; else if (!strcasecmp(status, "paused")) return AVRCP_PLAY_STATUS_PAUSED; else if (!strcasecmp(status, "forward-seek")) return AVRCP_PLAY_STATUS_FWD_SEEK; else if (!strcasecmp(status, "reverse-seek")) return AVRCP_PLAY_STATUS_REV_SEEK; else if (!strcasecmp(status, "error")) return AVRCP_PLAY_STATUS_ERROR; return -EINVAL; } static int metadata_to_val(const char *str) { if (!strcasecmp(str, "Title")) return AVRCP_MEDIA_ATTRIBUTE_TITLE; else if (!strcasecmp(str, "Artist")) return AVRCP_MEDIA_ATTRIBUTE_ARTIST; else if (!strcasecmp(str, "Album")) return AVRCP_MEDIA_ATTRIBUTE_ALBUM; else if (!strcasecmp(str, "Genre")) return AVRCP_MEDIA_ATTRIBUTE_GENRE; else if (!strcasecmp(str, "NumberOfTracks")) return AVRCP_MEDIA_ATTRIBUTE_N_TRACKS; else if (!strcasecmp(str, "Number")) return AVRCP_MEDIA_ATTRIBUTE_TRACK; else if (!strcasecmp(str, "Duration")) return AVRCP_MEDIA_ATTRIBUTE_DURATION; return -EINVAL; } static const char *metadata_to_str(uint32_t id) { switch (id) { case AVRCP_MEDIA_ATTRIBUTE_TITLE: return "Title"; case AVRCP_MEDIA_ATTRIBUTE_ARTIST: return "Artist"; case AVRCP_MEDIA_ATTRIBUTE_ALBUM: return "Album"; case AVRCP_MEDIA_ATTRIBUTE_GENRE: return "Genre"; case AVRCP_MEDIA_ATTRIBUTE_TRACK: return "Track"; case AVRCP_MEDIA_ATTRIBUTE_N_TRACKS: return "NumberOfTracks"; case AVRCP_MEDIA_ATTRIBUTE_DURATION: return "Duration"; } return NULL; } static int get_setting(uint8_t attr, void *user_data) { struct media_player *mp = user_data; guint attr_uint = attr; void *value; DBG("%s", attr_to_str(attr)); value = g_hash_table_lookup(mp->settings, GUINT_TO_POINTER(attr_uint)); if (!value) return -EINVAL; return GPOINTER_TO_UINT(value); } static int set_setting(uint8_t attr, uint8_t val, void *user_data) { struct media_player *mp = user_data; struct media_adapter *adapter = mp->adapter; const char *property, *value; guint attr_uint = attr; DBusMessage *msg; DBusMessageIter iter, var; property = attr_to_str(attr); value = attrval_to_str(attr, val); DBG("%s = %s", property, value); if (property == NULL || value == NULL) return -EINVAL; if (!g_hash_table_lookup(mp->settings, GUINT_TO_POINTER(attr_uint))) return -EINVAL; msg = dbus_message_new_method_call(mp->sender, mp->path, MEDIA_PLAYER_INTERFACE, "SetProperty"); if (msg == NULL) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_iter_init_append(msg, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property); dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &var); dbus_message_iter_append_basic(&var, DBUS_TYPE_STRING, &value); dbus_message_iter_close_container(&iter, &var); g_dbus_send_message(adapter->conn, msg); return 0; } static GList *list_metadata(void *user_data) { struct media_player *mp = user_data; DBG(""); if (mp->track == NULL) return NULL; return g_hash_table_get_keys(mp->track); } static uint64_t get_uid(void *user_data) { struct media_player *mp = user_data; DBG("%p", mp->track); if (mp->track == NULL) return UINT64_MAX; return 0; } static void *get_metadata(uint32_t id, void *user_data) { struct media_player *mp = user_data; struct metadata_value *value; DBG("%s", metadata_to_str(id)); if (mp->track == NULL) return NULL; value = g_hash_table_lookup(mp->track, GUINT_TO_POINTER(id)); if (!value) return NULL; switch (value->type) { case DBUS_TYPE_STRING: return value->value.str; case DBUS_TYPE_UINT32: return GUINT_TO_POINTER(value->value.num); } return NULL; } static uint8_t get_status(void *user_data) { struct media_player *mp = user_data; return mp->status; } static uint32_t get_position(void *user_data) { struct media_player *mp = user_data; double timedelta; uint32_t sec, msec; if (mp->status != AVRCP_PLAY_STATUS_PLAYING) return mp->position; timedelta = g_timer_elapsed(mp->timer, NULL); sec = (uint32_t) timedelta; msec = (uint32_t) ((timedelta - sec) * 1000); return mp->position + sec * 1000 + msec; } static void set_volume(uint8_t volume, struct audio_device *dev, void *user_data) { struct media_player *mp = user_data; GSList *l; if (mp->volume == volume) return; mp->volume = volume; for (l = mp->adapter->endpoints; l; l = l->next) { struct media_endpoint *endpoint = l->data; struct media_transport *transport; /* Volume is A2DP only */ if (endpoint->sep == NULL) continue; transport = find_device_transport(endpoint, dev); if (transport == NULL) continue; media_transport_update_volume(transport, volume); } } static struct avrcp_player_cb player_cb = { .get_setting = get_setting, .set_setting = set_setting, .list_metadata = list_metadata, .get_uid = get_uid, .get_metadata = get_metadata, .get_position = get_position, .get_status = get_status, .set_volume = set_volume }; static void media_player_exit(DBusConnection *connection, void *user_data) { struct media_player *mp = user_data; mp->watch = 0; media_player_remove(mp); } static gboolean set_status(struct media_player *mp, DBusMessageIter *iter) { const char *value; int val; if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) return FALSE; dbus_message_iter_get_basic(iter, &value); DBG("Status=%s", value); val = play_status_to_val(value); if (val < 0) { error("Invalid status"); return FALSE; } if (mp->status == val) return TRUE; mp->position = get_position(mp); g_timer_start(mp->timer); mp->status = val; avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, &val); return TRUE; } static gboolean set_position(struct media_player *mp, DBusMessageIter *iter) { uint32_t value; struct metadata_value *duration; if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32) return FALSE; dbus_message_iter_get_basic(iter, &value); DBG("Position=%u", value); mp->position = value; g_timer_start(mp->timer); if (!mp->position) { avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_START, NULL); return TRUE; } duration = g_hash_table_lookup(mp->track, GUINT_TO_POINTER( AVRCP_MEDIA_ATTRIBUTE_DURATION)); /* * If position is the maximum value allowed or greater than track's * duration, we send a track-reached-end event. */ if (mp->position == UINT32_MAX || (duration && mp->position >= duration->value.num)) avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_END, NULL); return TRUE; } static gboolean set_property(struct media_player *mp, const char *key, DBusMessageIter *entry) { DBusMessageIter var; const char *value; int attr, val; if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT) return FALSE; dbus_message_iter_recurse(entry, &var); if (strcasecmp(key, "Status") == 0) return set_status(mp, &var); if (strcasecmp(key, "Position") == 0) return set_position(mp, &var); attr = attr_to_val(key); if (attr < 0) return FALSE; if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING) return FALSE; dbus_message_iter_get_basic(&var, &value); val = attrval_to_val(attr, value); if (val < 0) return FALSE; DBG("%s=%s", key, value); g_hash_table_replace(mp->settings, GUINT_TO_POINTER(attr), GUINT_TO_POINTER(val)); return TRUE; } static gboolean property_changed(DBusConnection *connection, DBusMessage *msg, void *user_data) { struct media_player *mp = user_data; DBusMessageIter iter; const char *property; DBG("sender=%s path=%s", mp->sender, mp->path); dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { error("Unexpected signature in %s.%s signal", dbus_message_get_interface(msg), dbus_message_get_member(msg)); return TRUE; } dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); set_property(mp, property, &iter); return TRUE; } static void metadata_value_free(gpointer data) { struct metadata_value *value = data; switch (value->type) { case DBUS_TYPE_STRING: g_free(value->value.str); break; } g_free(value); } static gboolean parse_player_metadata(struct media_player *mp, DBusMessageIter *iter) { DBusMessageIter dict; DBusMessageIter var; GHashTable *track; int ctype; gboolean title = FALSE; uint64_t uid; ctype = dbus_message_iter_get_arg_type(iter); if (ctype != DBUS_TYPE_ARRAY) return FALSE; dbus_message_iter_recurse(iter, &dict); track = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, metadata_value_free); while ((ctype = dbus_message_iter_get_arg_type(&dict)) != DBUS_TYPE_INVALID) { DBusMessageIter entry; const char *key; struct metadata_value *value; int id; if (ctype != DBUS_TYPE_DICT_ENTRY) goto parse_error; dbus_message_iter_recurse(&dict, &entry); if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) goto parse_error; dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); id = metadata_to_val(key); if (id < 0) goto parse_error; if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT) goto parse_error; dbus_message_iter_recurse(&entry, &var); value = g_new0(struct metadata_value, 1); value->type = dbus_message_iter_get_arg_type(&var); switch (id) { case AVRCP_MEDIA_ATTRIBUTE_TITLE: title = TRUE; case AVRCP_MEDIA_ATTRIBUTE_ARTIST: case AVRCP_MEDIA_ATTRIBUTE_ALBUM: case AVRCP_MEDIA_ATTRIBUTE_GENRE: if (value->type != DBUS_TYPE_STRING) { g_free(value); goto parse_error; } dbus_message_iter_get_basic(&var, &value->value.str); break; case AVRCP_MEDIA_ATTRIBUTE_TRACK: case AVRCP_MEDIA_ATTRIBUTE_N_TRACKS: case AVRCP_MEDIA_ATTRIBUTE_DURATION: if (value->type != DBUS_TYPE_UINT32) { g_free(value); goto parse_error; } dbus_message_iter_get_basic(&var, &value->value.num); break; default: goto parse_error; } switch (value->type) { case DBUS_TYPE_STRING: value->value.str = g_strdup(value->value.str); DBG("%s=%s", key, value->value.str); break; default: DBG("%s=%u", key, value->value.num); } g_hash_table_replace(track, GUINT_TO_POINTER(id), value); dbus_message_iter_next(&dict); } if (g_hash_table_size(track) == 0) { g_hash_table_unref(track); track = NULL; } else if (title == FALSE) { struct metadata_value *value = g_new(struct metadata_value, 1); uint32_t id = AVRCP_MEDIA_ATTRIBUTE_TITLE; value->type = DBUS_TYPE_STRING; value->value.str = g_strdup(""); g_hash_table_insert(track, GUINT_TO_POINTER(id), value); } if (mp->track != NULL) g_hash_table_unref(mp->track); mp->track = track; mp->position = 0; g_timer_start(mp->timer); uid = get_uid(mp); avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_CHANGED, &uid); avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_START, NULL); return TRUE; parse_error: if (track) g_hash_table_unref(track); return FALSE; } static gboolean track_changed(DBusConnection *connection, DBusMessage *msg, void *user_data) { struct media_player *mp = user_data; DBusMessageIter iter; DBG("sender=%s path=%s", mp->sender, mp->path); dbus_message_iter_init(msg, &iter); if (parse_player_metadata(mp, &iter) == FALSE) { error("Unexpected signature in %s.%s signal", dbus_message_get_interface(msg), dbus_message_get_member(msg)); } return TRUE; } static struct media_player *media_player_create(struct media_adapter *adapter, const char *sender, const char *path, int *err) { struct media_player *mp; mp = g_new0(struct media_player, 1); mp->adapter = adapter; mp->sender = g_strdup(sender); mp->path = g_strdup(path); mp->timer = g_timer_new(); mp->watch = g_dbus_add_disconnect_watch(adapter->conn, sender, media_player_exit, mp, NULL); mp->property_watch = g_dbus_add_signal_watch(adapter->conn, sender, path, MEDIA_PLAYER_INTERFACE, "PropertyChanged", property_changed, mp, NULL); mp->track_watch = g_dbus_add_signal_watch(adapter->conn, sender, path, MEDIA_PLAYER_INTERFACE, "TrackChanged", track_changed, mp, NULL); mp->player = avrcp_register_player(&adapter->src, &player_cb, mp, media_player_free); if (!mp->player) { if (err) *err = -EPROTONOSUPPORT; media_player_destroy(mp); return NULL; } mp->settings = g_hash_table_new(g_direct_hash, g_direct_equal); adapter->players = g_slist_append(adapter->players, mp); info("Player registered: sender=%s path=%s", sender, path); if (err) *err = 0; return mp; } static gboolean parse_player_properties(struct media_player *mp, DBusMessageIter *iter) { DBusMessageIter dict; int ctype; ctype = dbus_message_iter_get_arg_type(iter); if (ctype != DBUS_TYPE_ARRAY) return FALSE; dbus_message_iter_recurse(iter, &dict); while ((ctype = dbus_message_iter_get_arg_type(&dict)) != DBUS_TYPE_INVALID) { DBusMessageIter entry; const char *key; if (ctype != DBUS_TYPE_DICT_ENTRY) return FALSE; dbus_message_iter_recurse(&dict, &entry); if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING) return FALSE; dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); if (set_property(mp, key, &entry) == FALSE) return FALSE; dbus_message_iter_next(&dict); } return TRUE; } static DBusMessage *register_player(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_adapter *adapter = data; struct media_player *mp; DBusMessageIter args; const char *sender, *path; int err; sender = dbus_message_get_sender(msg); dbus_message_iter_init(msg, &args); dbus_message_iter_get_basic(&args, &path); dbus_message_iter_next(&args); if (media_adapter_find_player(adapter, sender, path) != NULL) return btd_error_already_exists(msg); mp = media_player_create(adapter, sender, path, &err); if (mp == NULL) { if (err == -EPROTONOSUPPORT) return btd_error_not_supported(msg); else return btd_error_invalid_args(msg); } if (parse_player_properties(mp, &args) == FALSE) { media_player_destroy(mp); return btd_error_invalid_args(msg); } dbus_message_iter_next(&args); if (parse_player_metadata(mp, &args) == FALSE) { media_player_destroy(mp); return btd_error_invalid_args(msg); } return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static DBusMessage *unregister_player(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_adapter *adapter = data; struct media_player *player; const char *sender, *path; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return NULL; sender = dbus_message_get_sender(msg); player = media_adapter_find_player(adapter, sender, path); if (player == NULL) return btd_error_does_not_exist(msg); media_player_remove(player); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static const GDBusMethodTable media_methods[] = { { GDBUS_METHOD("RegisterEndpoint", GDBUS_ARGS({ "endpoint", "o" }, { "properties", "a{sv}" }), NULL, register_endpoint) }, { GDBUS_METHOD("UnregisterEndpoint", GDBUS_ARGS({ "endpoint", "o" }), NULL, unregister_endpoint) }, { GDBUS_METHOD("RegisterPlayer", GDBUS_ARGS({ "player", "o" }, { "properties", "a{sv}" }, { "metadata", "a{sv}" }), NULL, register_player) }, { GDBUS_METHOD("UnregisterPlayer", GDBUS_ARGS({ "player", "o" }), NULL, unregister_player) }, { }, }; static void path_free(void *data) { struct media_adapter *adapter = data; while (adapter->endpoints) release_endpoint(adapter->endpoints->data); dbus_connection_unref(adapter->conn); adapters = g_slist_remove(adapters, adapter); g_free(adapter->path); g_free(adapter); } int media_register(DBusConnection *conn, const char *path, const bdaddr_t *src) { struct media_adapter *adapter; adapter = g_new0(struct media_adapter, 1); adapter->conn = dbus_connection_ref(conn); bacpy(&adapter->src, src); adapter->path = g_strdup(path); if (!g_dbus_register_interface(conn, path, MEDIA_INTERFACE, media_methods, NULL, NULL, adapter, path_free)) { error("D-Bus failed to register %s path", path); path_free(adapter); return -1; } adapters = g_slist_append(adapters, adapter); return 0; } void media_unregister(const char *path) { GSList *l; for (l = adapters; l; l = l->next) { struct media_adapter *adapter = l->data; if (g_strcmp0(path, adapter->path) == 0) { g_dbus_unregister_interface(adapter->conn, path, MEDIA_INTERFACE); return; } } } struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint) { return endpoint->sep; } const char *media_endpoint_get_uuid(struct media_endpoint *endpoint) { return endpoint->uuid; } uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint) { return endpoint->codec; } bluez-4.101/audio/gstsbcparse.c0000644000000000000000000001335411766125764013341 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "gstpragma.h" #include "gstsbcutil.h" #include "gstsbcparse.h" GST_DEBUG_CATEGORY_STATIC(sbc_parse_debug); #define GST_CAT_DEFAULT sbc_parse_debug GST_BOILERPLATE(GstSbcParse, gst_sbc_parse, GstElement, GST_TYPE_ELEMENT); static const GstElementDetails sbc_parse_details = GST_ELEMENT_DETAILS("Bluetooth SBC parser", "Codec/Parser/Audio", "Parse a SBC audio stream", "Marcel Holtmann "); static GstStaticPadTemplate sbc_parse_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-sbc," "parsed = (boolean) false")); static GstStaticPadTemplate sbc_parse_src_factory = GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-sbc, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, " "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " "allocation = (string) { \"snr\", \"loudness\" }," "bitpool = (int) [ 2, 64 ]," "parsed = (boolean) true")); static GstFlowReturn sbc_parse_chain(GstPad *pad, GstBuffer *buffer) { GstSbcParse *parse = GST_SBC_PARSE(gst_pad_get_parent(pad)); GstFlowReturn res = GST_FLOW_OK; guint size, offset = 0; guint8 *data; /* FIXME use a gstadpter */ if (parse->buffer) { GstBuffer *temp; temp = buffer; buffer = gst_buffer_span(parse->buffer, 0, buffer, GST_BUFFER_SIZE(parse->buffer) + GST_BUFFER_SIZE(buffer)); gst_buffer_unref(parse->buffer); gst_buffer_unref(temp); parse->buffer = NULL; } data = GST_BUFFER_DATA(buffer); size = GST_BUFFER_SIZE(buffer); while (offset < size) { GstBuffer *output; int consumed; consumed = sbc_parse(&parse->new_sbc, data + offset, size - offset); if (consumed <= 0) break; if (parse->first_parsing || (memcmp(&parse->sbc, &parse->new_sbc, sizeof(sbc_t)) != 0)) { memcpy(&parse->sbc, &parse->new_sbc, sizeof(sbc_t)); if (parse->outcaps != NULL) gst_caps_unref(parse->outcaps); parse->outcaps = gst_sbc_parse_caps_from_sbc( &parse->sbc); parse->first_parsing = FALSE; } res = gst_pad_alloc_buffer_and_set_caps(parse->srcpad, GST_BUFFER_OFFSET_NONE, consumed, parse->outcaps, &output); if (res != GST_FLOW_OK) goto done; memcpy(GST_BUFFER_DATA(output), data + offset, consumed); res = gst_pad_push(parse->srcpad, output); if (res != GST_FLOW_OK) goto done; offset += consumed; } if (offset < size) parse->buffer = gst_buffer_create_sub(buffer, offset, size - offset); done: gst_buffer_unref(buffer); gst_object_unref(parse); return res; } static GstStateChangeReturn sbc_parse_change_state(GstElement *element, GstStateChange transition) { GstSbcParse *parse = GST_SBC_PARSE(element); switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: GST_DEBUG("Setup subband codec"); parse->channels = -1; parse->rate = -1; parse->first_parsing = TRUE; sbc_init(&parse->sbc, 0); break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG("Finish subband codec"); if (parse->buffer) { gst_buffer_unref(parse->buffer); parse->buffer = NULL; } if (parse->outcaps != NULL) { gst_caps_unref(parse->outcaps); parse->outcaps = NULL; } sbc_finish(&parse->sbc); break; default: break; } return parent_class->change_state(element, transition); } static void gst_sbc_parse_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sbc_parse_sink_factory)); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sbc_parse_src_factory)); gst_element_class_set_details(element_class, &sbc_parse_details); } static void gst_sbc_parse_class_init(GstSbcParseClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS(klass); parent_class = g_type_class_peek_parent(klass); element_class->change_state = GST_DEBUG_FUNCPTR(sbc_parse_change_state); GST_DEBUG_CATEGORY_INIT(sbc_parse_debug, "sbcparse", 0, "SBC parsing element"); } static void gst_sbc_parse_init(GstSbcParse *self, GstSbcParseClass *klass) { self->sinkpad = gst_pad_new_from_static_template( &sbc_parse_sink_factory, "sink"); gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_parse_chain)); gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); self->srcpad = gst_pad_new_from_static_template( &sbc_parse_src_factory, "src"); gst_element_add_pad(GST_ELEMENT(self), self->srcpad); self->outcaps = NULL; self->buffer = NULL; self->channels = -1; self->rate = -1; self->first_parsing = TRUE; } gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin) { return gst_element_register(plugin, "sbcparse", GST_RANK_NONE, GST_TYPE_SBC_PARSE); } bluez-4.101/audio/gateway.c0000644000000000000000000005226311766125764012464 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2008-2009 Leonid Movshovich * Copyright (C) 2010 ProFUSION embedded systems * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "sdp-client.h" #include "device.h" #include "gateway.h" #include "log.h" #include "error.h" #include "btio.h" #include "dbus-common.h" struct hf_agent { char *name; /* Bus id */ char *path; /* D-Bus path */ guint watch; /* Disconnect watch */ }; struct connect_cb { unsigned int id; gateway_stream_cb_t cb; void *cb_data; }; struct gateway { gateway_state_t state; GIOChannel *rfcomm; GIOChannel *sco; GIOChannel *incoming; GSList *callbacks; struct hf_agent *agent; DBusMessage *msg; int version; gateway_lock_t lock; }; struct gateway_state_callback { gateway_state_cb cb; void *user_data; unsigned int id; }; static GSList *gateway_callbacks = NULL; int gateway_close(struct audio_device *device); GQuark gateway_error_quark(void) { return g_quark_from_static_string("gateway-error-quark"); } static const char *state2str(gateway_state_t state) { switch (state) { case GATEWAY_STATE_DISCONNECTED: return "disconnected"; case GATEWAY_STATE_CONNECTING: return "connecting"; case GATEWAY_STATE_CONNECTED: return "connected"; case GATEWAY_STATE_PLAYING: return "playing"; default: return ""; } } static void agent_free(struct hf_agent *agent) { if (!agent) return; g_free(agent->name); g_free(agent->path); g_free(agent); } static void change_state(struct audio_device *dev, gateway_state_t new_state) { struct gateway *gw = dev->gateway; const char *val; GSList *l; gateway_state_t old_state; if (gw->state == new_state) return; val = state2str(new_state); old_state = gw->state; gw->state = new_state; emit_property_changed(dev->conn, dev->path, AUDIO_GATEWAY_INTERFACE, "State", DBUS_TYPE_STRING, &val); for (l = gateway_callbacks; l != NULL; l = l->next) { struct gateway_state_callback *cb = l->data; cb->cb(dev, old_state, new_state, cb->user_data); } } void gateway_set_state(struct audio_device *dev, gateway_state_t new_state) { switch (new_state) { case GATEWAY_STATE_DISCONNECTED: gateway_close(dev); break; case GATEWAY_STATE_CONNECTING: case GATEWAY_STATE_CONNECTED: case GATEWAY_STATE_PLAYING: break; } } static void agent_disconnect(struct audio_device *dev, struct hf_agent *agent) { DBusMessage *msg; msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.HandsfreeAgent", "Release"); g_dbus_send_message(dev->conn, msg); } static gboolean agent_sendfd(struct hf_agent *agent, int fd, DBusPendingCallNotifyFunction notify, void *data) { struct audio_device *dev = data; struct gateway *gw = dev->gateway; DBusMessage *msg; DBusPendingCall *call; msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.HandsfreeAgent", "NewConnection"); dbus_message_append_args(msg, DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_UINT16, &gw->version, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(dev->conn, msg, &call, -1) == FALSE) { dbus_message_unref(msg); return FALSE; } dbus_pending_call_set_notify(call, notify, dev, NULL); dbus_pending_call_unref(call); dbus_message_unref(msg); return TRUE; } static unsigned int connect_cb_new(struct gateway *gw, gateway_stream_cb_t func, void *user_data) { struct connect_cb *cb; static unsigned int free_cb_id = 1; if (!func) return 0; cb = g_new(struct connect_cb, 1); cb->cb = func; cb->cb_data = user_data; cb->id = free_cb_id++; gw->callbacks = g_slist_append(gw->callbacks, cb); return cb->id; } static void run_connect_cb(struct audio_device *dev, GError *err) { struct gateway *gw = dev->gateway; GSList *l; for (l = gw->callbacks; l != NULL; l = l->next) { struct connect_cb *cb = l->data; cb->cb(dev, err, cb->cb_data); } g_slist_free_full(gw->callbacks, g_free); gw->callbacks = NULL; } static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond, struct audio_device *dev) { struct gateway *gw = dev->gateway; if (cond & G_IO_NVAL) return FALSE; DBG("sco connection is released"); g_io_channel_shutdown(gw->sco, TRUE, NULL); g_io_channel_unref(gw->sco); gw->sco = NULL; change_state(dev, GATEWAY_STATE_CONNECTED); return FALSE; } static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct audio_device *dev = (struct audio_device *) user_data; struct gateway *gw = dev->gateway; DBG("at the begin of sco_connect_cb() in gateway.c"); gw->sco = g_io_channel_ref(chan); if (err) { error("sco_connect_cb(): %s", err->message); gateway_suspend_stream(dev); return; } g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) sco_io_cb, dev); change_state(dev, GATEWAY_STATE_PLAYING); run_connect_cb(dev, NULL); } static gboolean rfcomm_disconnect_cb(GIOChannel *chan, GIOCondition cond, struct audio_device *dev) { if (cond & G_IO_NVAL) return FALSE; gateway_close(dev); return FALSE; } static void newconnection_reply(DBusPendingCall *call, void *data) { struct audio_device *dev = data; struct gateway *gw = dev->gateway; DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError derr; if (!dev->gateway->rfcomm) { DBG("RFCOMM disconnected from server before agent reply"); goto done; } dbus_error_init(&derr); if (!dbus_set_error_from_message(&derr, reply)) { DBG("Agent reply: file descriptor passed successfully"); g_io_add_watch(gw->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_disconnect_cb, dev); change_state(dev, GATEWAY_STATE_CONNECTED); goto done; } DBG("Agent reply: %s", derr.message); dbus_error_free(&derr); gateway_close(dev); done: dbus_message_unref(reply); } static void rfcomm_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; DBusMessage *reply; int sk, ret; if (err) { error("connect(): %s", err->message); goto fail; } if (!gw->agent) { error("Handsfree Agent not registered"); goto fail; } sk = g_io_channel_unix_get_fd(chan); if (gw->rfcomm == NULL) gw->rfcomm = g_io_channel_ref(chan); ret = agent_sendfd(gw->agent, sk, newconnection_reply, dev); if (!gw->msg) return; if (ret) reply = dbus_message_new_method_return(gw->msg); else reply = btd_error_failed(gw->msg, "Can't pass file descriptor"); g_dbus_send_message(dev->conn, reply); return; fail: if (gw->msg) { DBusMessage *reply; reply = btd_error_failed(gw->msg, "Connect failed"); g_dbus_send_message(dev->conn, reply); } gateway_close(dev); } static int get_remote_profile_version(sdp_record_t *rec) { uuid_t uuid; sdp_list_t *profiles; sdp_profile_desc_t *desc; int ver = 0; sdp_uuid16_create(&uuid, HANDSFREE_PROFILE_ID); sdp_get_profile_descs(rec, &profiles); if (profiles == NULL) goto done; desc = profiles->data; if (sdp_uuid16_cmp(&desc->uuid, &uuid) == 0) ver = desc->version; sdp_list_free(profiles, free); done: return ver; } static void get_incoming_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; GError *gerr = NULL; if (err < 0) { error("Unable to get service record: %s (%d)", strerror(-err), -err); goto fail; } if (!recs || !recs->data) { error("No records found"); goto fail; } gw->version = get_remote_profile_version(recs->data); if (gw->version == 0) goto fail; rfcomm_connect_cb(gw->incoming, gerr, dev); return; fail: gateway_close(dev); } static void unregister_incoming(gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; if (gw->incoming) { g_io_channel_unref(gw->incoming); gw->incoming = NULL; } } static void rfcomm_incoming_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; uuid_t uuid; gw->incoming = g_io_channel_ref(chan); sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID); if (bt_search_service(&dev->src, &dev->dst, &uuid, get_incoming_record_cb, dev, unregister_incoming) == 0) return; unregister_incoming(dev); gateway_close(dev); } static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; int ch; sdp_list_t *protos, *classes; uuid_t uuid; GIOChannel *io; GError *gerr = NULL; if (err < 0) { error("Unable to get service record: %s (%d)", strerror(-err), -err); goto fail; } if (!recs || !recs->data) { error("No records found"); err = -EIO; goto fail; } if (sdp_get_service_classes(recs->data, &classes) < 0) { error("Unable to get service classes from record"); err = -EINVAL; goto fail; } if (sdp_get_access_protos(recs->data, &protos) < 0) { error("Unable to get access protocols from record"); err = -ENODATA; goto fail; } gw->version = get_remote_profile_version(recs->data); if (gw->version == 0) { error("Unable to get profile version from record"); err = -EINVAL; goto fail; } memcpy(&uuid, classes->data, sizeof(uuid)); sdp_list_free(classes, free); if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 || uuid.value.uuid16 != HANDSFREE_AGW_SVCLASS_ID) { sdp_list_free(protos, NULL); error("Invalid service record or not HFP"); err = -EIO; goto fail; } ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); if (ch <= 0) { error("Unable to extract RFCOMM channel from service record"); err = -EIO; goto fail; } io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, dev, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &dev->src, BT_IO_OPT_DEST_BDADDR, &dev->dst, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_CHANNEL, ch, BT_IO_OPT_INVALID); if (!io) { error("Unable to connect: %s", gerr->message); goto fail; } g_io_channel_unref(io); return; fail: if (gw->msg) { DBusMessage *reply = btd_error_failed(gw->msg, gerr ? gerr->message : strerror(-err)); g_dbus_send_message(dev->conn, reply); } gateway_close(dev); if (gerr) g_error_free(gerr); } static int get_records(struct audio_device *device) { uuid_t uuid; change_state(device, GATEWAY_STATE_CONNECTING); sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID); return bt_search_service(&device->src, &device->dst, &uuid, get_record_cb, device, NULL); } static DBusMessage *ag_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *au_dev = (struct audio_device *) data; struct gateway *gw = au_dev->gateway; int err; if (!gw->agent) return btd_error_agent_not_available(msg); err = get_records(au_dev); if (err < 0) return btd_error_failed(msg, strerror(-err)); gw->msg = dbus_message_ref(msg); return NULL; } int gateway_close(struct audio_device *device) { GError *gerr = NULL; struct gateway *gw = device->gateway; int sock; if (gw->rfcomm) { sock = g_io_channel_unix_get_fd(gw->rfcomm); shutdown(sock, SHUT_RDWR); g_io_channel_shutdown(gw->rfcomm, TRUE, NULL); g_io_channel_unref(gw->rfcomm); gw->rfcomm = NULL; } if (gw->sco) { g_io_channel_shutdown(gw->sco, TRUE, NULL); g_io_channel_unref(gw->sco); gw->sco = NULL; } change_state(device, GATEWAY_STATE_DISCONNECTED); g_set_error(&gerr, GATEWAY_ERROR, GATEWAY_ERROR_DISCONNECTED, "Disconnected"); run_connect_cb(device, gerr); g_error_free(gerr); return 0; } static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct gateway *gw = device->gateway; DBusMessage *reply = NULL; char gw_addr[18]; if (!device->conn) return NULL; if (!gw->rfcomm) return btd_error_not_connected(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; gateway_close(device); ba2str(&device->dst, gw_addr); DBG("Disconnected from %s, %s", gw_addr, device->path); return reply; } static void agent_exited(DBusConnection *conn, void *data) { struct gateway *gateway = data; struct hf_agent *agent = gateway->agent; DBG("Agent %s exited", agent->name); agent_free(agent); gateway->agent = NULL; } static DBusMessage *ag_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct gateway *gw = device->gateway; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; const char *value; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); value = state2str(gw->state); dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &value); dbus_message_iter_close_container(&iter, &dict); return reply; } static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct gateway *gw = device->gateway; struct hf_agent *agent; const char *path, *name; if (gw->agent) return btd_error_already_exists(msg); if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); name = dbus_message_get_sender(msg); agent = g_new0(struct hf_agent, 1); agent->name = g_strdup(name); agent->path = g_strdup(path); agent->watch = g_dbus_add_disconnect_watch(conn, name, agent_exited, gw, NULL); gw->agent = agent; return dbus_message_new_method_return(msg); } static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct gateway *gw = device->gateway; const char *path; if (!gw->agent) goto done; if (strcmp(gw->agent->name, dbus_message_get_sender(msg)) != 0) return btd_error_not_authorized(msg); if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); if (strcmp(gw->agent->path, path) != 0) return btd_error_does_not_exist(msg); g_dbus_remove_watch(device->conn, gw->agent->watch); agent_free(gw->agent); gw->agent = NULL; done: return dbus_message_new_method_return(msg); } static const GDBusMethodTable gateway_methods[] = { { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, ag_connect) }, { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, ag_disconnect) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), ag_get_properties) }, { GDBUS_METHOD("RegisterAgent", GDBUS_ARGS({ "agent", "o" }), NULL, register_agent) }, { GDBUS_METHOD("UnregisterAgent", GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) }, { } }; static const GDBusSignalTable gateway_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static void path_unregister(void *data) { struct audio_device *dev = data; DBG("Unregistered interface %s on path %s", AUDIO_GATEWAY_INTERFACE, dev->path); gateway_close(dev); g_free(dev->gateway); dev->gateway = NULL; } void gateway_unregister(struct audio_device *dev) { if (dev->gateway->agent) agent_disconnect(dev, dev->gateway->agent); g_dbus_unregister_interface(dev->conn, dev->path, AUDIO_GATEWAY_INTERFACE); } struct gateway *gateway_init(struct audio_device *dev) { if (!g_dbus_register_interface(dev->conn, dev->path, AUDIO_GATEWAY_INTERFACE, gateway_methods, gateway_signals, NULL, dev, path_unregister)) return NULL; return g_new0(struct gateway, 1); } gboolean gateway_is_connected(struct audio_device *dev) { struct gateway *gw = dev->gateway; if (gw->state == GATEWAY_STATE_CONNECTED) return TRUE; return FALSE; } gboolean gateway_is_active(struct audio_device *dev) { struct gateway *gw = dev->gateway; if (gw->state != GATEWAY_STATE_DISCONNECTED) return TRUE; return FALSE; } int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io) { if (!io) return -EINVAL; dev->gateway->rfcomm = g_io_channel_ref(io); change_state(dev, GATEWAY_STATE_CONNECTING); return 0; } int gateway_connect_sco(struct audio_device *dev, GIOChannel *io) { struct gateway *gw = dev->gateway; if (gw->sco) return -EISCONN; gw->sco = g_io_channel_ref(io); g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) sco_io_cb, dev); change_state(dev, GATEWAY_STATE_PLAYING); return 0; } void gateway_start_service(struct audio_device *dev) { struct gateway *gw = dev->gateway; GError *err = NULL; if (gw->rfcomm == NULL) return; if (!bt_io_accept(gw->rfcomm, rfcomm_incoming_cb, dev, NULL, &err)) { error("bt_io_accept: %s", err->message); g_error_free(err); gateway_close(dev); } } static gboolean request_stream_cb(gpointer data) { run_connect_cb(data, NULL); return FALSE; } /* These are functions to be called from unix.c for audio system * ifaces (alsa, gstreamer, etc.) */ unsigned int gateway_request_stream(struct audio_device *dev, gateway_stream_cb_t cb, void *user_data) { struct gateway *gw = dev->gateway; GError *err = NULL; GIOChannel *io; if (!gw->rfcomm) get_records(dev); else if (!gw->sco) { io = bt_io_connect(BT_IO_SCO, sco_connect_cb, dev, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &dev->src, BT_IO_OPT_DEST_BDADDR, &dev->dst, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID); if (!io) { error("%s", err->message); g_error_free(err); return 0; } } else g_idle_add(request_stream_cb, dev); return connect_cb_new(gw, cb, user_data); } int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t cb, void *user_data) { struct gateway *gw = dev->gateway; unsigned int id; id = connect_cb_new(gw, cb, user_data); if (!gw->rfcomm) get_records(dev); else if (cb) g_idle_add(request_stream_cb, dev); return id; } gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id) { struct gateway *gw = dev->gateway; GSList *l; struct connect_cb *cb = NULL; for (l = gw->callbacks; l != NULL; l = l->next) { struct connect_cb *tmp = l->data; if (tmp->id == id) { cb = tmp; break; } } if (!cb) return FALSE; gw->callbacks = g_slist_remove(gw->callbacks, cb); g_free(cb); gateway_suspend_stream(dev); return TRUE; } int gateway_get_sco_fd(struct audio_device *dev) { struct gateway *gw = dev->gateway; if (!gw || !gw->sco) return -1; return g_io_channel_unix_get_fd(gw->sco); } void gateway_suspend_stream(struct audio_device *dev) { GError *gerr = NULL; struct gateway *gw = dev->gateway; if (!gw || !gw->sco) return; g_io_channel_shutdown(gw->sco, TRUE, NULL); g_io_channel_unref(gw->sco); gw->sco = NULL; g_set_error(&gerr, GATEWAY_ERROR, GATEWAY_ERROR_SUSPENDED, "Suspended"); run_connect_cb(dev, gerr); g_error_free(gerr); change_state(dev, GATEWAY_STATE_CONNECTED); } unsigned int gateway_add_state_cb(gateway_state_cb cb, void *user_data) { struct gateway_state_callback *state_cb; static unsigned int id = 0; state_cb = g_new(struct gateway_state_callback, 1); state_cb->cb = cb; state_cb->user_data = user_data; state_cb->id = ++id; gateway_callbacks = g_slist_append(gateway_callbacks, state_cb); return state_cb->id; } gboolean gateway_remove_state_cb(unsigned int id) { GSList *l; for (l = gateway_callbacks; l != NULL; l = l->next) { struct gateway_state_callback *cb = l->data; if (cb && cb->id == id) { gateway_callbacks = g_slist_remove(gateway_callbacks, cb); g_free(cb); return TRUE; } } return FALSE; } gateway_lock_t gateway_get_lock(struct audio_device *dev) { struct gateway *gw = dev->gateway; return gw->lock; } gboolean gateway_lock(struct audio_device *dev, gateway_lock_t lock) { struct gateway *gw = dev->gateway; if (gw->lock & lock) return FALSE; gw->lock |= lock; return TRUE; } gboolean gateway_unlock(struct audio_device *dev, gateway_lock_t lock) { struct gateway *gw = dev->gateway; if (!(gw->lock & lock)) return FALSE; gw->lock &= ~lock; if (gw->lock) return TRUE; if (gw->state == GATEWAY_STATE_PLAYING) gateway_suspend_stream(dev); return TRUE; } bluez-4.101/audio/ctl_bluetooth.c0000644000000000000000000002043611766125764013667 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "ipc.h" #ifdef ENABLE_DEBUG #define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg) #else #define DBG(fmt, arg...) #endif #define BLUETOOTH_MINVOL 0 #define BLUETOOTH_MAXVOL 15 struct bluetooth_data { snd_ctl_ext_t ext; int sock; }; enum { BLUETOOTH_PLAYBACK, BLUETOOTH_CAPTURE, }; static const char *vol_devices[2] = { [BLUETOOTH_PLAYBACK] = "Playback volume", [BLUETOOTH_CAPTURE] = "Capture volume", }; static void bluetooth_exit(struct bluetooth_data *data) { if (data == NULL) return; if (data->sock >= 0) bt_audio_service_close(data->sock); free(data); } static void bluetooth_close(snd_ctl_ext_t *ext) { struct bluetooth_data *data = ext->private_data; DBG("ext %p", ext); bluetooth_exit(data); } static int bluetooth_elem_count(snd_ctl_ext_t *ext) { DBG("ext %p", ext); return 2; } static int bluetooth_elem_list(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id) { DBG("ext %p offset %d id %p", ext, offset, id); snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); if (offset > 1) return -EINVAL; snd_ctl_elem_id_set_name(id, vol_devices[offset]); return 0; } static snd_ctl_ext_key_t bluetooth_find_elem(snd_ctl_ext_t *ext, const snd_ctl_elem_id_t *id) { const char *name = snd_ctl_elem_id_get_name(id); int i; DBG("ext %p id %p name '%s'", ext, id, name); for (i = 0; i < 2; i++) if (strcmp(name, vol_devices[i]) == 0) return i; return SND_CTL_EXT_KEY_NOT_FOUND; } static int bluetooth_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int *type, unsigned int *acc, unsigned int *count) { DBG("ext %p key %ld", ext, key); *type = SND_CTL_ELEM_TYPE_INTEGER; *acc = SND_CTL_EXT_ACCESS_READWRITE; *count = 1; return 0; } static int bluetooth_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *imin, long *imax, long *istep) { DBG("ext %p key %ld", ext, key); *istep = 1; *imin = BLUETOOTH_MINVOL; *imax = BLUETOOTH_MAXVOL; return 0; } static int bluetooth_send_ctl(struct bluetooth_data *data, uint8_t mode, uint8_t key, struct bt_control_rsp *rsp) { int ret; struct bt_control_req *req = (void *) rsp; bt_audio_error_t *err = (void *) rsp; const char *type, *name; memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); req->h.type = BT_REQUEST; req->h.name = BT_CONTROL; req->h.length = sizeof(*req); req->mode = mode; req->key = key; ret = send(data->sock, req, BT_SUGGESTED_BUFFER_SIZE, MSG_NOSIGNAL); if (ret <= 0) { SYSERR("Unable to request new volume value to server"); return -errno; } ret = recv(data->sock, rsp, BT_SUGGESTED_BUFFER_SIZE, 0); if (ret <= 0) { SNDERR("Unable to receive new volume value from server"); return -errno; } if (rsp->h.type == BT_ERROR) { SNDERR("BT_CONTROL failed : %s (%d)", strerror(err->posix_errno), err->posix_errno); return -err->posix_errno; } type = bt_audio_strtype(rsp->h.type); if (!type) { SNDERR("Bogus message type %d " "received from audio service", rsp->h.type); return -EINVAL; } name = bt_audio_strname(rsp->h.name); if (!name) { SNDERR("Bogus message name %d " "received from audio service", rsp->h.name); return -EINVAL; } if (rsp->h.name != BT_CONTROL) { SNDERR("Unexpected message %s received", type); return -EINVAL; } return 0; } static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value) { struct bluetooth_data *data = ext->private_data; int ret; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_control_rsp *rsp = (void *) buf; DBG("ext %p key %ld", ext, key); memset(buf, 0, sizeof(buf)); *value = 0; ret = bluetooth_send_ctl(data, key, 0, rsp); if (ret == 0) *value = rsp->key; return ret; } static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value) { struct bluetooth_data *data = ext->private_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_control_rsp *rsp = (void *) buf; long current; int ret, keyvalue; DBG("ext %p key %ld", ext, key); ret = bluetooth_read_integer(ext, key, ¤t); if (ret < 0) return ret; if (*value == current) return 0; while (*value != current) { keyvalue = (*value > current) ? BT_CONTROL_KEY_VOL_UP : BT_CONTROL_KEY_VOL_DOWN; ret = bluetooth_send_ctl(data, key, keyvalue, rsp); if (ret < 0) break; current = keyvalue; } return ret; } static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id, unsigned int *event_mask) { struct bluetooth_data *data = ext->private_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_control_ind *ind = (void *) buf; int err; const char *type, *name; DBG("ext %p id %p", ext, id); memset(buf, 0, sizeof(buf)); err = recv(data->sock, ind, BT_SUGGESTED_BUFFER_SIZE, MSG_DONTWAIT); if (err < 0) { err = -errno; SNDERR("Failed while receiving data: %s (%d)", strerror(-err), -err); return err; } type = bt_audio_strtype(ind->h.type); if (!type) { SNDERR("Bogus message type %d " "received from audio service", ind->h.type); return -EAGAIN; } name = bt_audio_strname(ind->h.name); if (!name) { SNDERR("Bogus message name %d " "received from audio service", ind->h.name); return -EAGAIN; } if (ind->h.name != BT_CONTROL) { SNDERR("Unexpected message %s received", name); return -EAGAIN; } snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_name(id, ind->mode == BLUETOOTH_PLAYBACK ? vol_devices[BLUETOOTH_PLAYBACK] : vol_devices[BLUETOOTH_CAPTURE]); *event_mask = SND_CTL_EVENT_MASK_VALUE; return 1; } static snd_ctl_ext_callback_t bluetooth_callback = { .close = bluetooth_close, .elem_count = bluetooth_elem_count, .elem_list = bluetooth_elem_list, .find_elem = bluetooth_find_elem, .get_attribute = bluetooth_get_attribute, .get_integer_info = bluetooth_get_integer_info, .read_integer = bluetooth_read_integer, .write_integer = bluetooth_write_integer, .read_event = bluetooth_read_event, }; static int bluetooth_init(struct bluetooth_data *data) { int sk; if (!data) return -EINVAL; memset(data, 0, sizeof(struct bluetooth_data)); data->sock = -1; sk = bt_audio_service_open(); if (sk < 0) return -errno; data->sock = sk; return 0; } SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth); SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth) { struct bluetooth_data *data; int err; DBG("Bluetooth Control plugin"); data = malloc(sizeof(struct bluetooth_data)); if (!data) { err = -ENOMEM; goto error; } err = bluetooth_init(data); if (err < 0) goto error; data->ext.version = SND_CTL_EXT_VERSION; data->ext.card_idx = -1; strncpy(data->ext.id, "bluetooth", sizeof(data->ext.id) - 1); strncpy(data->ext.driver, "Bluetooth-Audio", sizeof(data->ext.driver) - 1); strncpy(data->ext.name, "Bluetooth Audio", sizeof(data->ext.name) - 1); strncpy(data->ext.longname, "Bluetooth Audio", sizeof(data->ext.longname) - 1); strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1); data->ext.callback = &bluetooth_callback; data->ext.poll_fd = data->sock; data->ext.private_data = data; err = snd_ctl_ext_create(&data->ext, name, mode); if (err < 0) goto error; *handlep = data->ext.handle; return 0; error: bluetooth_exit(data); return err; } SND_CTL_PLUGIN_SYMBOL(bluetooth); bluez-4.101/audio/source.c0000644000000000000000000003454211766125764012323 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2009 Joao Paulo Rechi Vita * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "log.h" #include "device.h" #include "avdtp.h" #include "media.h" #include "a2dp.h" #include "error.h" #include "source.h" #include "dbus-common.h" #include "../src/adapter.h" #include "../src/device.h" #define STREAM_SETUP_RETRY_TIMER 2 struct pending_request { DBusConnection *conn; DBusMessage *msg; unsigned int id; }; struct source { struct audio_device *dev; struct avdtp *session; struct avdtp_stream *stream; unsigned int cb_id; guint retry_id; avdtp_session_state_t session_state; avdtp_state_t stream_state; source_state_t state; struct pending_request *connect; struct pending_request *disconnect; DBusConnection *conn; }; struct source_state_callback { source_state_cb cb; void *user_data; unsigned int id; }; static GSList *source_callbacks = NULL; static unsigned int avdtp_callback_id = 0; static const char *state2str(source_state_t state) { switch (state) { case SOURCE_STATE_DISCONNECTED: return "disconnected"; case SOURCE_STATE_CONNECTING: return "connecting"; case SOURCE_STATE_CONNECTED: return "connected"; case SOURCE_STATE_PLAYING: return "playing"; default: error("Invalid source state %d", state); return NULL; } } static void source_set_state(struct audio_device *dev, source_state_t new_state) { struct source *source = dev->source; const char *state_str; source_state_t old_state = source->state; GSList *l; source->state = new_state; state_str = state2str(new_state); if (state_str) emit_property_changed(dev->conn, dev->path, AUDIO_SOURCE_INTERFACE, "State", DBUS_TYPE_STRING, &state_str); for (l = source_callbacks; l != NULL; l = l->next) { struct source_state_callback *cb = l->data; cb->cb(dev, old_state, new_state, cb->user_data); } } static void avdtp_state_callback(struct audio_device *dev, struct avdtp *session, avdtp_session_state_t old_state, avdtp_session_state_t new_state, void *user_data) { struct source *source = dev->source; if (source == NULL) return; switch (new_state) { case AVDTP_SESSION_STATE_DISCONNECTED: source_set_state(dev, SOURCE_STATE_DISCONNECTED); break; case AVDTP_SESSION_STATE_CONNECTING: source_set_state(dev, SOURCE_STATE_CONNECTING); break; case AVDTP_SESSION_STATE_CONNECTED: break; } source->session_state = new_state; } static void pending_request_free(struct audio_device *dev, struct pending_request *pending) { if (pending->conn) dbus_connection_unref(pending->conn); if (pending->msg) dbus_message_unref(pending->msg); if (pending->id) a2dp_cancel(dev, pending->id); g_free(pending); } 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 audio_device *dev = user_data; struct source *source = dev->source; if (err) return; switch (new_state) { case AVDTP_STATE_IDLE: if (source->disconnect) { DBusMessage *reply; struct pending_request *p; p = source->disconnect; source->disconnect = NULL; reply = dbus_message_new_method_return(p->msg); g_dbus_send_message(p->conn, reply); pending_request_free(dev, p); } if (source->session) { avdtp_unref(source->session); source->session = NULL; } source->stream = NULL; source->cb_id = 0; break; case AVDTP_STATE_OPEN: source_set_state(dev, SOURCE_STATE_CONNECTED); break; case AVDTP_STATE_STREAMING: source_set_state(dev, SOURCE_STATE_PLAYING); break; case AVDTP_STATE_CONFIGURED: case AVDTP_STATE_CLOSING: case AVDTP_STATE_ABORTING: default: break; } source->stream_state = new_state; } static void error_failed(DBusConnection *conn, DBusMessage *msg, const char *desc) { DBusMessage *reply = btd_error_failed(msg, desc); g_dbus_send_message(conn, reply); } static gboolean stream_setup_retry(gpointer user_data) { struct source *source = user_data; struct pending_request *pending = source->connect; source->retry_id = 0; if (source->stream_state >= AVDTP_STATE_OPEN) { DBG("Stream successfully created, after XCASE connect:connect"); if (pending->msg) { DBusMessage *reply; reply = dbus_message_new_method_return(pending->msg); g_dbus_send_message(pending->conn, reply); } } else { DBG("Stream setup failed, after XCASE connect:connect"); if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); } source->connect = NULL; pending_request_free(source->dev, pending); return FALSE; } static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct source *source = user_data; struct pending_request *pending; pending = source->connect; pending->id = 0; if (stream) { DBG("Stream successfully created"); if (pending->msg) { DBusMessage *reply; reply = dbus_message_new_method_return(pending->msg); g_dbus_send_message(pending->conn, reply); } source->connect = NULL; pending_request_free(source->dev, pending); return; } avdtp_unref(source->session); source->session = NULL; if (avdtp_error_category(err) == AVDTP_ERRNO && avdtp_error_posix_errno(err) != EHOSTDOWN) { DBG("connect:connect XCASE detected"); source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER, stream_setup_retry, source); } else { if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); source->connect = NULL; pending_request_free(source->dev, pending); DBG("Stream setup failed : %s", avdtp_strerror(err)); } } static void select_complete(struct avdtp *session, struct a2dp_sep *sep, GSList *caps, void *user_data) { struct source *source = user_data; struct pending_request *pending; int id; pending = source->connect; pending->id = 0; if (caps == NULL) goto failed; id = a2dp_config(session, sep, stream_setup_complete, caps, source); if (id == 0) goto failed; pending->id = id; return; failed: if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); pending_request_free(source->dev, pending); source->connect = NULL; avdtp_unref(source->session); source->session = NULL; } static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err, void *user_data) { struct source *source = user_data; struct pending_request *pending; int id; pending = source->connect; if (err) { avdtp_unref(source->session); source->session = NULL; if (avdtp_error_category(err) == AVDTP_ERRNO && avdtp_error_posix_errno(err) != EHOSTDOWN) { DBG("connect:connect XCASE detected"); source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER, stream_setup_retry, source); } else goto failed; return; } DBG("Discovery complete"); id = a2dp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE, NULL, select_complete, source); if (id == 0) goto failed; pending->id = id; return; failed: if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); pending_request_free(source->dev, pending); source->connect = NULL; avdtp_unref(source->session); source->session = NULL; } gboolean source_setup_stream(struct source *source, struct avdtp *session) { if (source->connect || source->disconnect) return FALSE; if (session && !source->session) source->session = avdtp_ref(session); if (!source->session) return FALSE; avdtp_set_auto_disconnect(source->session, FALSE); if (avdtp_discover(source->session, discovery_complete, source) < 0) return FALSE; source->connect = g_new0(struct pending_request, 1); return TRUE; } static DBusMessage *source_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct source *source = dev->source; struct pending_request *pending; if (!source->session) source->session = avdtp_get(&dev->src, &dev->dst); if (!source->session) return btd_error_failed(msg, "Unable to get a session"); if (source->connect || source->disconnect) return btd_error_busy(msg); if (source->stream_state >= AVDTP_STATE_OPEN) return btd_error_already_connected(msg); if (!source_setup_stream(source, NULL)) return btd_error_failed(msg, "Failed to create a stream"); dev->auto_connect = FALSE; pending = source->connect; pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); DBG("stream creation in progress"); return NULL; } static DBusMessage *source_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct source *source = device->source; struct pending_request *pending; int err; if (!source->session) return btd_error_not_connected(msg); if (source->connect || source->disconnect) return btd_error_busy(msg); if (source->stream_state < AVDTP_STATE_OPEN) { DBusMessage *reply = dbus_message_new_method_return(msg); if (!reply) return NULL; avdtp_unref(source->session); source->session = NULL; return reply; } err = avdtp_close(source->session, source->stream, FALSE); if (err < 0) return btd_error_failed(msg, strerror(-err)); pending = g_new0(struct pending_request, 1); pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); source->disconnect = pending; return NULL; } static DBusMessage *source_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct source *source = device->source; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; const char *state; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* State */ state = state2str(source->state); if (state) dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state); dbus_message_iter_close_container(&iter, &dict); return reply; } static const GDBusMethodTable source_methods[] = { { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, source_connect) }, { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, source_disconnect) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), source_get_properties) }, { } }; static const GDBusSignalTable source_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static void source_free(struct audio_device *dev) { struct source *source = dev->source; 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) pending_request_free(dev, source->connect); if (source->disconnect) pending_request_free(dev, source->disconnect); if (source->retry_id) g_source_remove(source->retry_id); g_free(source); dev->source = NULL; } static void path_unregister(void *data) { struct audio_device *dev = data; DBG("Unregistered interface %s on path %s", AUDIO_SOURCE_INTERFACE, dev->path); source_free(dev); } void source_unregister(struct audio_device *dev) { g_dbus_unregister_interface(dev->conn, dev->path, AUDIO_SOURCE_INTERFACE); } struct source *source_init(struct audio_device *dev) { struct source *source; if (!g_dbus_register_interface(dev->conn, dev->path, AUDIO_SOURCE_INTERFACE, source_methods, source_signals, NULL, dev, path_unregister)) return NULL; DBG("Registered interface %s on path %s", AUDIO_SOURCE_INTERFACE, dev->path); if (avdtp_callback_id == 0) avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback, NULL); source = g_new0(struct source, 1); source->dev = dev; return source; } gboolean source_is_active(struct audio_device *dev) { struct source *source = dev->source; if (source->session) return TRUE; return FALSE; } source_state_t source_get_state(struct audio_device *dev) { struct source *source = dev->source; return source->state; } gboolean source_new_stream(struct audio_device *dev, struct avdtp *session, struct avdtp_stream *stream) { struct source *source = dev->source; 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, dev); return TRUE; } gboolean source_shutdown(struct source *source) { if (!source->stream) return FALSE; if (avdtp_close(source->session, source->stream, FALSE) < 0) return FALSE; return TRUE; } unsigned int source_add_state_cb(source_state_cb cb, void *user_data) { struct source_state_callback *state_cb; static unsigned int id = 0; state_cb = g_new(struct source_state_callback, 1); state_cb->cb = cb; state_cb->user_data = user_data; state_cb->id = ++id; source_callbacks = g_slist_append(source_callbacks, state_cb); return state_cb->id; } gboolean source_remove_state_cb(unsigned int id) { GSList *l; for (l = source_callbacks; l != NULL; l = l->next) { struct source_state_callback *cb = l->data; if (cb && cb->id == id) { source_callbacks = g_slist_remove(source_callbacks, cb); g_free(cb); return TRUE; } } return FALSE; } bluez-4.101/audio/gstpragma.h0000644000000000000000000000166311571052274013000 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* #pragma GCC diagnostic warning "-Wmissing-declarations" */ bluez-4.101/audio/transport.c0000644000000000000000000006720211766125764013056 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2009 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "../src/adapter.h" #include "../src/dbus-common.h" #include "log.h" #include "error.h" #include "device.h" #include "avdtp.h" #include "media.h" #include "transport.h" #include "a2dp.h" #include "headset.h" #include "gateway.h" #include "avrcp.h" #define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport" struct media_request { DBusMessage *msg; guint id; }; struct media_owner { struct media_transport *transport; struct media_request *pending; char *name; char *accesstype; guint watch; }; struct a2dp_transport { struct avdtp *session; uint16_t delay; uint16_t volume; }; struct headset_transport { struct audio_device *device; unsigned int nrec_id; }; struct media_transport { DBusConnection *conn; char *path; /* Transport object path */ struct audio_device *device; /* Transport device */ struct media_endpoint *endpoint; /* Transport endpoint */ GSList *owners; /* Transport owners */ uint8_t *configuration; /* Transport configuration */ int size; /* Transport configuration size */ int fd; /* Transport file descriptor */ uint16_t imtu; /* Transport input mtu */ uint16_t omtu; /* Transport output mtu */ gboolean read_lock; gboolean write_lock; gboolean in_use; guint (*resume) (struct media_transport *transport, struct media_owner *owner); guint (*suspend) (struct media_transport *transport, struct media_owner *owner); void (*cancel) (struct media_transport *transport, guint id); void (*get_properties) ( struct media_transport *transport, DBusMessageIter *dict); int (*set_property) ( struct media_transport *transport, const char *property, DBusMessageIter *value); GDestroyNotify destroy; void *data; }; void media_transport_destroy(struct media_transport *transport) { char *path; path = g_strdup(transport->path); g_dbus_unregister_interface(transport->conn, path, MEDIA_TRANSPORT_INTERFACE); g_free(path); } static struct media_request *media_request_create(DBusMessage *msg, guint id) { struct media_request *req; req = g_new0(struct media_request, 1); req->msg = dbus_message_ref(msg); req->id = id; DBG("Request created: method=%s id=%u", dbus_message_get_member(msg), id); return req; } static void media_request_reply(struct media_request *req, DBusConnection *conn, int err) { DBusMessage *reply; DBG("Request %s Reply %s", dbus_message_get_member(req->msg), strerror(err)); if (!err) reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID); else reply = g_dbus_create_error(req->msg, ERROR_INTERFACE ".Failed", "%s", strerror(err)); g_dbus_send_message(conn, reply); } static gboolean media_transport_release(struct media_transport *transport, const char *accesstype) { if (g_strstr_len(accesstype, -1, "r") != NULL) { transport->read_lock = FALSE; DBG("Transport %s: read lock released", transport->path); } if (g_strstr_len(accesstype, -1, "w") != NULL) { transport->write_lock = FALSE; DBG("Transport %s: write lock released", transport->path); } return TRUE; } static void media_owner_remove(struct media_owner *owner) { struct media_transport *transport = owner->transport; struct media_request *req = owner->pending; if (!req) return; DBG("Owner %s Request %s", owner->name, dbus_message_get_member(req->msg)); if (req->id) transport->cancel(transport, req->id); owner->pending = NULL; if (req->msg) dbus_message_unref(req->msg); g_free(req); } static void media_owner_free(struct media_owner *owner) { DBG("Owner %s", owner->name); media_owner_remove(owner); g_free(owner->name); g_free(owner->accesstype); g_free(owner); } static void media_transport_remove(struct media_transport *transport, struct media_owner *owner) { DBG("Transport %s Owner %s", transport->path, owner->name); media_transport_release(transport, owner->accesstype); /* Reply if owner has a pending request */ if (owner->pending) media_request_reply(owner->pending, transport->conn, EIO); transport->owners = g_slist_remove(transport->owners, owner); if (owner->watch) g_dbus_remove_watch(transport->conn, owner->watch); media_owner_free(owner); /* Suspend if there is no longer any owner */ if (transport->owners == NULL && transport->in_use) transport->suspend(transport, NULL); } static gboolean media_transport_set_fd(struct media_transport *transport, int fd, uint16_t imtu, uint16_t omtu) { if (transport->fd == fd) return TRUE; transport->fd = fd; transport->imtu = imtu; transport->omtu = omtu; info("%s: fd(%d) ready", transport->path, fd); return TRUE; } static void a2dp_resume_complete(struct avdtp *session, struct avdtp_error *err, void *user_data) { struct media_owner *owner = user_data; struct media_request *req = owner->pending; struct media_transport *transport = owner->transport; struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint); struct avdtp_stream *stream; int fd; uint16_t imtu, omtu; gboolean ret; req->id = 0; if (err) goto fail; stream = a2dp_sep_get_stream(sep); if (stream == NULL) goto fail; ret = avdtp_stream_get_transport(stream, &fd, &imtu, &omtu, NULL); if (ret == FALSE) goto fail; media_transport_set_fd(transport, fd, imtu, omtu); if (g_strstr_len(owner->accesstype, -1, "r") == NULL) imtu = 0; if (g_strstr_len(owner->accesstype, -1, "w") == NULL) omtu = 0; ret = g_dbus_send_reply(transport->conn, req->msg, DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_UINT16, &imtu, DBUS_TYPE_UINT16, &omtu, DBUS_TYPE_INVALID); if (ret == FALSE) goto fail; media_owner_remove(owner); return; fail: media_transport_remove(transport, owner); } static guint resume_a2dp(struct media_transport *transport, struct media_owner *owner) { struct a2dp_transport *a2dp = transport->data; struct media_endpoint *endpoint = transport->endpoint; struct audio_device *device = transport->device; struct a2dp_sep *sep = media_endpoint_get_sep(endpoint); if (a2dp->session == NULL) { a2dp->session = avdtp_get(&device->src, &device->dst); if (a2dp->session == NULL) return 0; } if (transport->in_use == TRUE) goto done; transport->in_use = a2dp_sep_lock(sep, a2dp->session); if (transport->in_use == FALSE) return 0; done: return a2dp_resume(a2dp->session, sep, a2dp_resume_complete, owner); } static void a2dp_suspend_complete(struct avdtp *session, struct avdtp_error *err, void *user_data) { struct media_owner *owner = user_data; struct media_transport *transport = owner->transport; struct a2dp_transport *a2dp = transport->data; struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint); /* Release always succeeds */ if (owner->pending) { owner->pending->id = 0; media_request_reply(owner->pending, transport->conn, 0); media_owner_remove(owner); } a2dp_sep_unlock(sep, a2dp->session); transport->in_use = FALSE; media_transport_remove(transport, owner); } static guint suspend_a2dp(struct media_transport *transport, struct media_owner *owner) { struct a2dp_transport *a2dp = transport->data; struct media_endpoint *endpoint = transport->endpoint; struct a2dp_sep *sep = media_endpoint_get_sep(endpoint); if (!owner) { a2dp_sep_unlock(sep, a2dp->session); transport->in_use = FALSE; return 0; } return a2dp_suspend(a2dp->session, sep, a2dp_suspend_complete, owner); } static void cancel_a2dp(struct media_transport *transport, guint id) { a2dp_cancel(transport->device, id); } static void headset_resume_complete(struct audio_device *dev, void *user_data) { struct media_owner *owner = user_data; struct media_request *req = owner->pending; struct media_transport *transport = owner->transport; int fd; uint16_t imtu, omtu; gboolean ret; req->id = 0; if (dev == NULL) goto fail; fd = headset_get_sco_fd(dev); if (fd < 0) goto fail; imtu = 48; omtu = 48; media_transport_set_fd(transport, fd, imtu, omtu); if (g_strstr_len(owner->accesstype, -1, "r") == NULL) imtu = 0; if (g_strstr_len(owner->accesstype, -1, "w") == NULL) omtu = 0; ret = g_dbus_send_reply(transport->conn, req->msg, DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_UINT16, &imtu, DBUS_TYPE_UINT16, &omtu, DBUS_TYPE_INVALID); if (ret == FALSE) goto fail; media_owner_remove(owner); return; fail: media_transport_remove(transport, owner); } static guint resume_headset(struct media_transport *transport, struct media_owner *owner) { struct audio_device *device = transport->device; if (transport->in_use == TRUE) goto done; transport->in_use = headset_lock(device, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE); if (transport->in_use == FALSE) return 0; done: return headset_request_stream(device, headset_resume_complete, owner); } static void headset_suspend_complete(struct audio_device *dev, void *user_data) { struct media_owner *owner = user_data; struct media_transport *transport = owner->transport; /* Release always succeeds */ if (owner->pending) { owner->pending->id = 0; media_request_reply(owner->pending, transport->conn, 0); media_owner_remove(owner); } headset_unlock(dev, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE); transport->in_use = FALSE; media_transport_remove(transport, owner); } static guint suspend_headset(struct media_transport *transport, struct media_owner *owner) { struct audio_device *device = transport->device; if (!owner) { headset_unlock(device, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE); transport->in_use = FALSE; return 0; } return headset_suspend_stream(device, headset_suspend_complete, owner); } static void cancel_headset(struct media_transport *transport, guint id) { headset_cancel_stream(transport->device, id); } static void gateway_resume_complete(struct audio_device *dev, GError *err, void *user_data) { struct media_owner *owner = user_data; struct media_request *req = owner->pending; struct media_transport *transport = owner->transport; int fd; uint16_t imtu, omtu; gboolean ret; req->id = 0; if (dev == NULL) goto fail; if (err) { error("Failed to resume gateway: error %s", err->message); goto fail; } fd = gateway_get_sco_fd(dev); if (fd < 0) goto fail; imtu = 48; omtu = 48; media_transport_set_fd(transport, fd, imtu, omtu); if (g_strstr_len(owner->accesstype, -1, "r") == NULL) imtu = 0; if (g_strstr_len(owner->accesstype, -1, "w") == NULL) omtu = 0; ret = g_dbus_send_reply(transport->conn, req->msg, DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_UINT16, &imtu, DBUS_TYPE_UINT16, &omtu, DBUS_TYPE_INVALID); if (ret == FALSE) goto fail; media_owner_remove(owner); return; fail: media_transport_remove(transport, owner); } static guint resume_gateway(struct media_transport *transport, struct media_owner *owner) { struct audio_device *device = transport->device; if (transport->in_use == TRUE) goto done; transport->in_use = gateway_lock(device, GATEWAY_LOCK_READ | GATEWAY_LOCK_WRITE); if (transport->in_use == FALSE) return 0; done: return gateway_request_stream(device, gateway_resume_complete, owner); } static gboolean gateway_suspend_complete(gpointer user_data) { struct media_owner *owner = user_data; struct media_transport *transport = owner->transport; struct audio_device *device = transport->device; /* Release always succeeds */ if (owner->pending) { owner->pending->id = 0; media_request_reply(owner->pending, transport->conn, 0); media_owner_remove(owner); } gateway_unlock(device, GATEWAY_LOCK_READ | GATEWAY_LOCK_WRITE); transport->in_use = FALSE; media_transport_remove(transport, owner); return FALSE; } static guint suspend_gateway(struct media_transport *transport, struct media_owner *owner) { struct audio_device *device = transport->device; static int id = 1; if (!owner) { gateway_unlock(device, GATEWAY_LOCK_READ | GATEWAY_LOCK_WRITE); transport->in_use = FALSE; return 0; } gateway_suspend_stream(device); g_idle_add(gateway_suspend_complete, owner); return id++; } static void cancel_gateway(struct media_transport *transport, guint id) { gateway_cancel_stream(transport->device, id); } static void media_owner_exit(DBusConnection *connection, void *user_data) { struct media_owner *owner = user_data; owner->watch = 0; media_owner_remove(owner); media_transport_remove(owner->transport, owner); } static gboolean media_transport_acquire(struct media_transport *transport, const char *accesstype) { gboolean read_lock = FALSE, write_lock = FALSE; if (g_strstr_len(accesstype, -1, "r") != NULL) { if (transport->read_lock == TRUE) return FALSE; read_lock = TRUE; } if (g_strstr_len(accesstype, -1, "w") != NULL) { if (transport->write_lock == TRUE) return FALSE; write_lock = TRUE; } /* Check invalid accesstype */ if (read_lock == FALSE && write_lock == FALSE) return FALSE; if (read_lock) { transport->read_lock = read_lock; DBG("Transport %s: read lock acquired", transport->path); } if (write_lock) { transport->write_lock = write_lock; DBG("Transport %s: write lock acquired", transport->path); } return TRUE; } static void media_transport_add(struct media_transport *transport, struct media_owner *owner) { DBG("Transport %s Owner %s", transport->path, owner->name); transport->owners = g_slist_append(transport->owners, owner); owner->transport = transport; owner->watch = g_dbus_add_disconnect_watch(transport->conn, owner->name, media_owner_exit, owner, NULL); } static struct media_owner *media_owner_create(DBusConnection *conn, DBusMessage *msg, const char *accesstype) { struct media_owner *owner; owner = g_new0(struct media_owner, 1); owner->name = g_strdup(dbus_message_get_sender(msg)); owner->accesstype = g_strdup(accesstype); DBG("Owner created: sender=%s accesstype=%s", owner->name, accesstype); return owner; } static void media_owner_add(struct media_owner *owner, struct media_request *req) { DBG("Owner %s Request %s", owner->name, dbus_message_get_member(req->msg)); owner->pending = req; } static struct media_owner *media_transport_find_owner( struct media_transport *transport, const char *name) { GSList *l; for (l = transport->owners; l; l = l->next) { struct media_owner *owner = l->data; if (g_strcmp0(owner->name, name) == 0) return owner; } return NULL; } static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_transport *transport = data; struct media_owner *owner; struct media_request *req; const char *accesstype, *sender; guint id; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID)) return NULL; sender = dbus_message_get_sender(msg); owner = media_transport_find_owner(transport, sender); if (owner != NULL) return btd_error_not_authorized(msg); if (media_transport_acquire(transport, accesstype) == FALSE) return btd_error_not_authorized(msg); owner = media_owner_create(conn, msg, accesstype); id = transport->resume(transport, owner); if (id == 0) { media_transport_release(transport, accesstype); media_owner_free(owner); return btd_error_not_authorized(msg); } req = media_request_create(msg, id); media_owner_add(owner, req); media_transport_add(transport, owner); return NULL; } static DBusMessage *release(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_transport *transport = data; struct media_owner *owner; const char *accesstype, *sender; struct media_request *req; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID)) return NULL; sender = dbus_message_get_sender(msg); owner = media_transport_find_owner(transport, sender); if (owner == NULL) return btd_error_not_authorized(msg); if (g_strcmp0(owner->accesstype, accesstype) == 0) { guint id; /* Not the last owner, no need to suspend */ if (g_slist_length(transport->owners) != 1) { media_transport_remove(transport, owner); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } if (owner->pending) { const char *member; member = dbus_message_get_member(owner->pending->msg); /* Cancel Acquire request if that exist */ if (g_str_equal(member, "Acquire")) media_owner_remove(owner); else return btd_error_in_progress(msg); } id = transport->suspend(transport, owner); if (id == 0) { media_transport_remove(transport, owner); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } req = media_request_create(msg, id); media_owner_add(owner, req); return NULL; } else if (g_strstr_len(owner->accesstype, -1, accesstype) != NULL) { media_transport_release(transport, accesstype); g_strdelimit(owner->accesstype, accesstype, ' '); } else return btd_error_not_authorized(msg); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static int set_property_a2dp(struct media_transport *transport, const char *property, DBusMessageIter *value) { struct a2dp_transport *a2dp = transport->data; if (g_strcmp0(property, "Delay") == 0) { if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) return -EINVAL; dbus_message_iter_get_basic(value, &a2dp->delay); /* FIXME: send new delay */ return 0; } else if (g_strcmp0(property, "Volume") == 0) { uint16_t volume; if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_UINT16) return -EINVAL; dbus_message_iter_get_basic(value, &volume); if (volume > 127) return -EINVAL; if (a2dp->volume == volume) return 0; return avrcp_set_volume(transport->device, volume); } return -EINVAL; } static int set_property_headset(struct media_transport *transport, const char *property, DBusMessageIter *value) { if (g_strcmp0(property, "NREC") == 0) { gboolean nrec; if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) return -EINVAL; dbus_message_iter_get_basic(value, &nrec); /* FIXME: set new nrec */ return 0; } else if (g_strcmp0(property, "InbandRingtone") == 0) { gboolean inband; if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) return -EINVAL; dbus_message_iter_get_basic(value, &inband); /* FIXME: set new inband */ return 0; } return -EINVAL; } static int set_property_gateway(struct media_transport *transport, const char *property, DBusMessageIter *value) { return -EINVAL; } static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_transport *transport = data; DBusMessageIter iter; DBusMessageIter value; const char *property, *sender; GSList *l; int err; if (!dbus_message_iter_init(msg, &iter)) return btd_error_invalid_args(msg); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return btd_error_invalid_args(msg); dbus_message_iter_recurse(&iter, &value); sender = dbus_message_get_sender(msg); err = -EINVAL; /* Check if sender has acquired the transport */ for (l = transport->owners; l; l = l->next) { struct media_owner *owner = l->data; if (g_strcmp0(owner->name, sender) == 0) { err = transport->set_property(transport, property, &value); break; } } if (err < 0) { if (err == -EINVAL) return btd_error_invalid_args(msg); return btd_error_failed(msg, strerror(-err)); } return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } static void get_properties_a2dp(struct media_transport *transport, DBusMessageIter *dict) { struct a2dp_transport *a2dp = transport->data; dict_append_entry(dict, "Delay", DBUS_TYPE_UINT16, &a2dp->delay); if (a2dp->volume <= 127) dict_append_entry(dict, "Volume", DBUS_TYPE_UINT16, &a2dp->volume); } static void get_properties_headset(struct media_transport *transport, DBusMessageIter *dict) { gboolean nrec, inband; const char *routing; nrec = headset_get_nrec(transport->device); dict_append_entry(dict, "NREC", DBUS_TYPE_BOOLEAN, &nrec); inband = headset_get_inband(transport->device); dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN, &inband); routing = headset_get_sco_hci(transport->device) ? "HCI" : "PCM"; dict_append_entry(dict, "Routing", DBUS_TYPE_STRING, &routing); } static void get_properties_gateway(struct media_transport *transport, DBusMessageIter *dict) { /* None */ } void transport_get_properties(struct media_transport *transport, DBusMessageIter *iter) { DBusMessageIter dict; const char *uuid; uint8_t codec; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Device */ dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH, &transport->device->path); uuid = media_endpoint_get_uuid(transport->endpoint); dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid); codec = media_endpoint_get_codec(transport->endpoint); dict_append_entry(&dict, "Codec", DBUS_TYPE_BYTE, &codec); dict_append_array(&dict, "Configuration", DBUS_TYPE_BYTE, &transport->configuration, transport->size); if (transport->get_properties) transport->get_properties(transport, &dict); dbus_message_iter_close_container(iter, &dict); } static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_transport *transport = data; DBusMessage *reply; DBusMessageIter iter; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); transport_get_properties(transport, &iter); return reply; } static const GDBusMethodTable transport_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), get_properties) }, { GDBUS_ASYNC_METHOD("Acquire", GDBUS_ARGS({ "access_type", "s" }), GDBUS_ARGS({ "fd", "h" }, { "mtu_r", "q" }, { "mtu_w", "q" } ), acquire) }, { GDBUS_ASYNC_METHOD("Release", GDBUS_ARGS({ "access_type", "s" }), NULL, release ) }, { GDBUS_ASYNC_METHOD("SetProperty", GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL, set_property) }, { }, }; static const GDBusSignalTable transport_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static void destroy_a2dp(void *data) { struct a2dp_transport *a2dp = data; if (a2dp->session) avdtp_unref(a2dp->session); g_free(a2dp); } static void destroy_headset(void *data) { struct headset_transport *headset = data; if (headset->nrec_id > 0) headset_remove_nrec_cb(headset->device, headset->nrec_id); g_free(headset); } static void media_transport_free(void *data) { struct media_transport *transport = data; GSList *l = transport->owners; while (l) { struct media_owner *owner = l->data; l = l->next; media_transport_remove(transport, owner); } g_slist_free(transport->owners); if (transport->destroy != NULL) transport->destroy(transport->data); if (transport->conn) dbus_connection_unref(transport->conn); g_free(transport->configuration); g_free(transport->path); g_free(transport); } static void headset_nrec_changed(struct audio_device *dev, gboolean nrec, void *user_data) { struct media_transport *transport = user_data; DBG(""); emit_property_changed(transport->conn, transport->path, MEDIA_TRANSPORT_INTERFACE, "NREC", DBUS_TYPE_BOOLEAN, &nrec); } struct media_transport *media_transport_create(DBusConnection *conn, struct media_endpoint *endpoint, struct audio_device *device, uint8_t *configuration, size_t size) { struct media_transport *transport; const char *uuid; static int fd = 0; transport = g_new0(struct media_transport, 1); transport->conn = dbus_connection_ref(conn); transport->device = device; transport->endpoint = endpoint; transport->configuration = g_new(uint8_t, size); memcpy(transport->configuration, configuration, size); transport->size = size; transport->path = g_strdup_printf("%s/fd%d", device->path, fd++); transport->fd = -1; uuid = media_endpoint_get_uuid(endpoint); if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0 || strcasecmp(uuid, A2DP_SINK_UUID) == 0) { struct a2dp_transport *a2dp; a2dp = g_new0(struct a2dp_transport, 1); a2dp->volume = -1; transport->resume = resume_a2dp; transport->suspend = suspend_a2dp; transport->cancel = cancel_a2dp; transport->get_properties = get_properties_a2dp; transport->set_property = set_property_a2dp; transport->data = a2dp; transport->destroy = destroy_a2dp; } else if (strcasecmp(uuid, HFP_AG_UUID) == 0 || strcasecmp(uuid, HSP_AG_UUID) == 0) { struct headset_transport *headset; headset = g_new0(struct headset_transport, 1); headset->device = device; headset->nrec_id = headset_add_nrec_cb(device, headset_nrec_changed, transport); transport->resume = resume_headset; transport->suspend = suspend_headset; transport->cancel = cancel_headset; transport->get_properties = get_properties_headset; transport->set_property = set_property_headset; transport->data = headset; transport->destroy = destroy_headset; } else if (strcasecmp(uuid, HFP_HS_UUID) == 0 || strcasecmp(uuid, HSP_HS_UUID) == 0) { transport->resume = resume_gateway; transport->suspend = suspend_gateway; transport->cancel = cancel_gateway; transport->get_properties = get_properties_gateway; transport->set_property = set_property_gateway; } else goto fail; if (g_dbus_register_interface(transport->conn, transport->path, MEDIA_TRANSPORT_INTERFACE, transport_methods, transport_signals, NULL, transport, media_transport_free) == FALSE) { error("Could not register transport %s", transport->path); goto fail; } return transport; fail: media_transport_free(transport); return NULL; } const char *media_transport_get_path(struct media_transport *transport) { return transport->path; } void media_transport_update_delay(struct media_transport *transport, uint16_t delay) { struct a2dp_transport *a2dp = transport->data; /* Check if delay really changed */ if (a2dp->delay == delay) return; a2dp->delay = delay; emit_property_changed(transport->conn, transport->path, MEDIA_TRANSPORT_INTERFACE, "Delay", DBUS_TYPE_UINT16, &a2dp->delay); } struct audio_device *media_transport_get_dev(struct media_transport *transport) { return transport->device; } void media_transport_update_volume(struct media_transport *transport, uint8_t volume) { struct a2dp_transport *a2dp = transport->data; /* Check if volume really changed */ if (a2dp->volume == volume) return; a2dp->volume = volume; emit_property_changed(transport->conn, transport->path, MEDIA_TRANSPORT_INTERFACE, "Volume", DBUS_TYPE_UINT16, &a2dp->volume); } bluez-4.101/audio/sink.h0000644000000000000000000000334411766125764011770 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define AUDIO_SINK_INTERFACE "org.bluez.AudioSink" typedef enum { SINK_STATE_DISCONNECTED, SINK_STATE_CONNECTING, SINK_STATE_CONNECTED, SINK_STATE_PLAYING, } sink_state_t; typedef void (*sink_state_cb) (struct audio_device *dev, sink_state_t old_state, sink_state_t new_state, void *user_data); unsigned int sink_add_state_cb(sink_state_cb cb, void *user_data); gboolean sink_remove_state_cb(unsigned int id); struct sink *sink_init(struct audio_device *dev); void sink_unregister(struct audio_device *dev); gboolean sink_is_active(struct audio_device *dev); sink_state_t sink_get_state(struct audio_device *dev); gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session, struct avdtp_stream *stream); gboolean sink_setup_stream(struct sink *sink, struct avdtp *session); gboolean sink_shutdown(struct sink *sink); bluez-4.101/audio/a2dp.h0000644000000000000000000001372711766125764011660 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2011 BMW Car IT GmbH. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define A2DP_CODEC_SBC 0x00 #define A2DP_CODEC_MPEG12 0x01 #define A2DP_CODEC_MPEG24 0x02 #define A2DP_CODEC_ATRAC 0x03 #define SBC_SAMPLING_FREQ_16000 (1 << 3) #define SBC_SAMPLING_FREQ_32000 (1 << 2) #define SBC_SAMPLING_FREQ_44100 (1 << 1) #define SBC_SAMPLING_FREQ_48000 1 #define SBC_CHANNEL_MODE_MONO (1 << 3) #define SBC_CHANNEL_MODE_DUAL_CHANNEL (1 << 2) #define SBC_CHANNEL_MODE_STEREO (1 << 1) #define SBC_CHANNEL_MODE_JOINT_STEREO 1 #define SBC_BLOCK_LENGTH_4 (1 << 3) #define SBC_BLOCK_LENGTH_8 (1 << 2) #define SBC_BLOCK_LENGTH_12 (1 << 1) #define SBC_BLOCK_LENGTH_16 1 #define SBC_SUBBANDS_4 (1 << 1) #define SBC_SUBBANDS_8 1 #define SBC_ALLOCATION_SNR (1 << 1) #define SBC_ALLOCATION_LOUDNESS 1 #define MPEG_CHANNEL_MODE_MONO (1 << 3) #define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2) #define MPEG_CHANNEL_MODE_STEREO (1 << 1) #define MPEG_CHANNEL_MODE_JOINT_STEREO 1 #define MPEG_LAYER_MP1 (1 << 2) #define MPEG_LAYER_MP2 (1 << 1) #define MPEG_LAYER_MP3 1 #define MPEG_SAMPLING_FREQ_16000 (1 << 5) #define MPEG_SAMPLING_FREQ_22050 (1 << 4) #define MPEG_SAMPLING_FREQ_24000 (1 << 3) #define MPEG_SAMPLING_FREQ_32000 (1 << 2) #define MPEG_SAMPLING_FREQ_44100 (1 << 1) #define MPEG_SAMPLING_FREQ_48000 1 #define MAX_BITPOOL 64 #define MIN_BITPOOL 2 #if __BYTE_ORDER == __LITTLE_ENDIAN struct sbc_codec_cap { struct avdtp_media_codec_capability cap; uint8_t channel_mode:4; uint8_t frequency:4; uint8_t allocation_method:2; uint8_t subbands:2; uint8_t block_length:4; uint8_t min_bitpool; uint8_t max_bitpool; } __attribute__ ((packed)); struct mpeg_codec_cap { struct avdtp_media_codec_capability cap; uint8_t channel_mode:4; uint8_t crc:1; uint8_t layer:3; uint8_t frequency:6; uint8_t mpf:1; uint8_t rfa:1; uint16_t bitrate; } __attribute__ ((packed)); #elif __BYTE_ORDER == __BIG_ENDIAN struct sbc_codec_cap { struct avdtp_media_codec_capability cap; uint8_t frequency:4; uint8_t channel_mode:4; uint8_t block_length:4; uint8_t subbands:2; uint8_t allocation_method:2; uint8_t min_bitpool; uint8_t max_bitpool; } __attribute__ ((packed)); struct mpeg_codec_cap { struct avdtp_media_codec_capability cap; uint8_t layer:3; uint8_t crc:1; uint8_t channel_mode:4; uint8_t rfa:1; uint8_t mpf:1; uint8_t frequency:6; uint16_t bitrate; } __attribute__ ((packed)); #else #error "Unknown byte order" #endif struct a2dp_sep; struct a2dp_setup; typedef void (*a2dp_endpoint_select_t) (struct a2dp_setup *setup, void *ret, int size); typedef void (*a2dp_endpoint_config_t) (struct a2dp_setup *setup, gboolean ret); struct a2dp_endpoint { const char *(*get_name) (struct a2dp_sep *sep, void *user_data); size_t (*get_capabilities) (struct a2dp_sep *sep, uint8_t **capabilities, void *user_data); int (*select_configuration) (struct a2dp_sep *sep, uint8_t *capabilities, size_t length, struct a2dp_setup *setup, a2dp_endpoint_select_t cb, void *user_data); int (*set_configuration) (struct a2dp_sep *sep, struct audio_device *dev, uint8_t *configuration, size_t length, struct a2dp_setup *setup, a2dp_endpoint_config_t cb, void *user_data); void (*clear_configuration) (struct a2dp_sep *sep, void *user_data); void (*set_delay) (struct a2dp_sep *sep, uint16_t delay, void *user_data); }; typedef void (*a2dp_select_cb_t) (struct avdtp *session, struct a2dp_sep *sep, GSList *caps, void *user_data); typedef void (*a2dp_config_cb_t) (struct avdtp *session, struct a2dp_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); typedef void (*a2dp_stream_cb_t) (struct avdtp *session, struct avdtp_error *err, void *user_data); int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config); void a2dp_unregister(const bdaddr_t *src); struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type, uint8_t codec, gboolean delay_reporting, struct a2dp_endpoint *endpoint, void *user_data, GDestroyNotify destroy, int *err); void a2dp_remove_sep(struct a2dp_sep *sep); struct a2dp_sep *a2dp_get(struct avdtp *session, struct avdtp_remote_sep *sep); unsigned int a2dp_select_capabilities(struct avdtp *session, uint8_t type, const char *sender, a2dp_select_cb_t cb, void *user_data); unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep, a2dp_config_cb_t cb, GSList *caps, void *user_data); unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep, a2dp_stream_cb_t cb, void *user_data); unsigned int a2dp_suspend(struct avdtp *session, struct a2dp_sep *sep, a2dp_stream_cb_t cb, void *user_data); gboolean a2dp_cancel(struct audio_device *dev, unsigned int id); gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session); gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session); gboolean a2dp_sep_get_lock(struct a2dp_sep *sep); struct avdtp_stream *a2dp_sep_get_stream(struct a2dp_sep *sep); struct a2dp_sep *a2dp_get_sep(struct avdtp *session, struct avdtp_stream *stream); bluez-4.101/audio/media.h0000644000000000000000000000270311766125764012101 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2009 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ struct media_endpoint; typedef void (*media_endpoint_cb_t) (struct media_endpoint *endpoint, void *ret, int size, void *user_data); int media_register(DBusConnection *conn, const char *path, const bdaddr_t *src); void media_unregister(const char *path); struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint); const char *media_endpoint_get_uuid(struct media_endpoint *endpoint); uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint); struct media_transport *media_endpoint_get_transport( struct media_endpoint *endpoint); bluez-4.101/audio/gstsbcdec.c0000644000000000000000000001334111766125764012756 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "gstpragma.h" #include "gstsbcutil.h" #include "gstsbcdec.h" GST_DEBUG_CATEGORY_STATIC(sbc_dec_debug); #define GST_CAT_DEFAULT sbc_dec_debug GST_BOILERPLATE(GstSbcDec, gst_sbc_dec, GstElement, GST_TYPE_ELEMENT); static const GstElementDetails sbc_dec_details = GST_ELEMENT_DETAILS("Bluetooth SBC decoder", "Codec/Decoder/Audio", "Decode a SBC audio stream", "Marcel Holtmann "); static GstStaticPadTemplate sbc_dec_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-sbc")); static GstStaticPadTemplate sbc_dec_src_factory = GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-raw-int, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " "endianness = (int) BYTE_ORDER, " "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16")); static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer) { GstSbcDec *dec = GST_SBC_DEC(gst_pad_get_parent(pad)); GstFlowReturn res = GST_FLOW_OK; guint size, codesize, offset = 0; guint8 *data; codesize = sbc_get_codesize(&dec->sbc); if (dec->buffer) { GstBuffer *temp = buffer; buffer = gst_buffer_span(dec->buffer, 0, buffer, GST_BUFFER_SIZE(dec->buffer) + GST_BUFFER_SIZE(buffer)); gst_buffer_unref(temp); gst_buffer_unref(dec->buffer); dec->buffer = NULL; } data = GST_BUFFER_DATA(buffer); size = GST_BUFFER_SIZE(buffer); while (offset < size) { GstBuffer *output; GstPadTemplate *template; GstCaps *caps; int consumed; res = gst_pad_alloc_buffer_and_set_caps(dec->srcpad, GST_BUFFER_OFFSET_NONE, codesize, NULL, &output); if (res != GST_FLOW_OK) goto done; consumed = sbc_decode(&dec->sbc, data + offset, size - offset, GST_BUFFER_DATA(output), codesize, NULL); if (consumed <= 0) break; /* we will reuse the same caps object */ if (dec->outcaps == NULL) { caps = gst_caps_new_simple("audio/x-raw-int", "rate", G_TYPE_INT, gst_sbc_parse_rate_from_sbc( dec->sbc.frequency), "channels", G_TYPE_INT, gst_sbc_get_channel_number( dec->sbc.mode), NULL); template = gst_static_pad_template_get(&sbc_dec_src_factory); dec->outcaps = gst_caps_intersect(caps, gst_pad_template_get_caps(template)); gst_caps_unref(caps); } gst_buffer_set_caps(output, dec->outcaps); /* FIXME get a real timestamp */ GST_BUFFER_TIMESTAMP(output) = GST_CLOCK_TIME_NONE; res = gst_pad_push(dec->srcpad, output); if (res != GST_FLOW_OK) goto done; offset += consumed; } if (offset < size) dec->buffer = gst_buffer_create_sub(buffer, offset, size - offset); done: gst_buffer_unref(buffer); gst_object_unref(dec); return res; } static GstStateChangeReturn sbc_dec_change_state(GstElement *element, GstStateChange transition) { GstSbcDec *dec = GST_SBC_DEC(element); switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: GST_DEBUG("Setup subband codec"); if (dec->buffer) { gst_buffer_unref(dec->buffer); dec->buffer = NULL; } sbc_init(&dec->sbc, 0); dec->outcaps = NULL; break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG("Finish subband codec"); if (dec->buffer) { gst_buffer_unref(dec->buffer); dec->buffer = NULL; } sbc_finish(&dec->sbc); if (dec->outcaps) { gst_caps_unref(dec->outcaps); dec->outcaps = NULL; } break; default: break; } return parent_class->change_state(element, transition); } static void gst_sbc_dec_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sbc_dec_sink_factory)); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sbc_dec_src_factory)); gst_element_class_set_details(element_class, &sbc_dec_details); } static void gst_sbc_dec_class_init(GstSbcDecClass *klass) { GstElementClass *element_class = GST_ELEMENT_CLASS(klass); parent_class = g_type_class_peek_parent(klass); element_class->change_state = GST_DEBUG_FUNCPTR(sbc_dec_change_state); GST_DEBUG_CATEGORY_INIT(sbc_dec_debug, "sbcdec", 0, "SBC decoding element"); } static void gst_sbc_dec_init(GstSbcDec *self, GstSbcDecClass *klass) { self->sinkpad = gst_pad_new_from_static_template( &sbc_dec_sink_factory, "sink"); gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR( sbc_dec_chain)); gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); self->srcpad = gst_pad_new_from_static_template( &sbc_dec_src_factory, "src"); gst_element_add_pad(GST_ELEMENT(self), self->srcpad); self->outcaps = NULL; } gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin) { return gst_element_register(plugin, "sbcdec", GST_RANK_PRIMARY, GST_TYPE_SBC_DEC); } bluez-4.101/audio/gstsbcdec.h0000644000000000000000000000335711571052274012756 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "sbc.h" G_BEGIN_DECLS #define GST_TYPE_SBC_DEC \ (gst_sbc_dec_get_type()) #define GST_SBC_DEC(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_DEC,GstSbcDec)) #define GST_SBC_DEC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_DEC,GstSbcDecClass)) #define GST_IS_SBC_DEC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_DEC)) #define GST_IS_SBC_DEC_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_DEC)) typedef struct _GstSbcDec GstSbcDec; typedef struct _GstSbcDecClass GstSbcDecClass; struct _GstSbcDec { GstElement element; GstPad *sinkpad; GstPad *srcpad; GstBuffer *buffer; /* caps for outgoing buffers */ GstCaps *outcaps; sbc_t sbc; }; struct _GstSbcDecClass { GstElementClass parent_class; }; GType gst_sbc_dec_get_type(void); gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin); G_END_DECLS bluez-4.101/audio/gstbluetooth.c0000644000000000000000000000514011571052274013523 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "gstsbcutil.h" #include #include "gstsbcenc.h" #include "gstsbcdec.h" #include "gstsbcparse.h" #include "gstavdtpsink.h" #include "gsta2dpsink.h" #include "gstrtpsbcpay.h" static GstStaticCaps sbc_caps = GST_STATIC_CAPS("audio/x-sbc"); #define SBC_CAPS (gst_static_caps_get(&sbc_caps)) static void sbc_typefind(GstTypeFind *tf, gpointer ignore) { GstCaps *caps; guint8 *aux; sbc_t sbc; guint8 *data = gst_type_find_peek(tf, 0, 32); if (data == NULL) return; if (sbc_init(&sbc, 0) < 0) return; aux = g_new(guint8, 32); memcpy(aux, data, 32); if (sbc_parse(&sbc, aux, 32) < 0) goto done; caps = gst_sbc_parse_caps_from_sbc(&sbc); gst_type_find_suggest(tf, GST_TYPE_FIND_POSSIBLE, caps); gst_caps_unref(caps); done: g_free(aux); sbc_finish(&sbc); } static gchar *sbc_exts[] = { "sbc", NULL }; static gboolean plugin_init(GstPlugin *plugin) { GST_INFO("Bluetooth plugin %s", VERSION); if (gst_type_find_register(plugin, "sbc", GST_RANK_PRIMARY, sbc_typefind, sbc_exts, SBC_CAPS, NULL, NULL) == FALSE) return FALSE; if (!gst_sbc_enc_plugin_init(plugin)) return FALSE; if (!gst_sbc_dec_plugin_init(plugin)) return FALSE; if (!gst_sbc_parse_plugin_init(plugin)) return FALSE; if (!gst_avdtp_sink_plugin_init(plugin)) return FALSE; if (!gst_a2dp_sink_plugin_init(plugin)) return FALSE; if (!gst_rtp_sbc_pay_plugin_init(plugin)) return FALSE; return TRUE; } extern GstPluginDesc gst_plugin_desc __attribute__ ((visibility("default"))); GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR, "bluetooth", "Bluetooth plugin library", plugin_init, VERSION, "LGPL", "BlueZ", "http://www.bluez.org/") bluez-4.101/audio/a2dp.c0000644000000000000000000015400411771117441011632 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2011 BMW Car IT GmbH. All rights reserved. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "log.h" #include "device.h" #include "manager.h" #include "avdtp.h" #include "sink.h" #include "source.h" #include "unix.h" #include "a2dp.h" #include "sdpd.h" /* The duration that streams without users are allowed to stay in * STREAMING state. */ #define SUSPEND_TIMEOUT 5 #define RECONFIGURE_TIMEOUT 500 #ifndef MIN # define MIN(x, y) ((x) < (y) ? (x) : (y)) #endif #ifndef MAX # define MAX(x, y) ((x) > (y) ? (x) : (y)) #endif struct a2dp_sep { struct a2dp_server *server; struct a2dp_endpoint *endpoint; uint8_t type; uint8_t codec; struct avdtp_local_sep *lsep; struct avdtp *session; struct avdtp_stream *stream; guint suspend_timer; gboolean delay_reporting; gboolean locked; gboolean suspending; gboolean starting; void *user_data; GDestroyNotify destroy; }; struct a2dp_setup_cb { struct a2dp_setup *setup; a2dp_select_cb_t select_cb; a2dp_config_cb_t config_cb; a2dp_stream_cb_t resume_cb; a2dp_stream_cb_t suspend_cb; guint source_id; void *user_data; unsigned int id; }; struct a2dp_setup { struct audio_device *dev; struct avdtp *session; struct a2dp_sep *sep; struct avdtp_remote_sep *rsep; struct avdtp_stream *stream; struct avdtp_error *err; avdtp_set_configuration_cb setconf_cb; GSList *caps; gboolean reconfigure; gboolean start; GSList *cb; int ref; }; static DBusConnection *connection = NULL; struct a2dp_server { bdaddr_t src; GSList *sinks; GSList *sources; uint32_t source_record_id; uint32_t sink_record_id; uint16_t version; gboolean sink_enabled; gboolean source_enabled; }; static GSList *servers = NULL; static GSList *setups = NULL; static unsigned int cb_id = 0; static struct a2dp_setup *setup_ref(struct a2dp_setup *setup) { setup->ref++; DBG("%p: ref=%d", setup, setup->ref); return setup; } static struct audio_device *a2dp_get_dev(struct avdtp *session) { bdaddr_t src, dst; avdtp_get_peers(session, &src, &dst); return manager_find_device(NULL, &src, &dst, NULL, FALSE); } static struct a2dp_setup *setup_new(struct avdtp *session) { struct audio_device *dev; struct a2dp_setup *setup; dev = a2dp_get_dev(session); if (!dev) { error("Unable to create setup"); return NULL; } setup = g_new0(struct a2dp_setup, 1); setup->session = avdtp_ref(session); setup->dev = a2dp_get_dev(session); setups = g_slist_append(setups, setup); return setup; } static void setup_free(struct a2dp_setup *s) { DBG("%p", s); setups = g_slist_remove(setups, s); if (s->session) avdtp_unref(s->session); g_slist_free_full(s->cb, g_free); g_slist_free_full(s->caps, g_free); g_free(s); } static void setup_unref(struct a2dp_setup *setup) { setup->ref--; DBG("%p: ref=%d", setup, setup->ref); if (setup->ref > 0) return; setup_free(setup); } static struct a2dp_setup_cb *setup_cb_new(struct a2dp_setup *setup) { struct a2dp_setup_cb *cb; cb = g_new0(struct a2dp_setup_cb, 1); cb->setup = setup; cb->id = ++cb_id; setup->cb = g_slist_append(setup->cb, cb); return cb; } static void setup_cb_free(struct a2dp_setup_cb *cb) { struct a2dp_setup *setup = cb->setup; if (cb->source_id) g_source_remove(cb->source_id); setup->cb = g_slist_remove(setup->cb, cb); setup_unref(cb->setup); g_free(cb); } static void finalize_setup_errno(struct a2dp_setup *s, int err, GSourceFunc cb1, ...) { GSourceFunc finalize; va_list args; struct avdtp_error avdtp_err; if (err < 0) { avdtp_error_init(&avdtp_err, AVDTP_ERRNO, -err); s->err = &avdtp_err; } va_start(args, cb1); finalize = cb1; setup_ref(s); while (finalize != NULL) { finalize(s); finalize = va_arg(args, GSourceFunc); } setup_unref(s); va_end(args); } static gboolean finalize_config(gpointer data) { struct a2dp_setup *s = data; GSList *l; struct avdtp_stream *stream = s->err ? NULL : s->stream; for (l = s->cb; l != NULL; ) { struct a2dp_setup_cb *cb = l->data; l = l->next; if (!cb->config_cb) continue; cb->config_cb(s->session, s->sep, stream, s->err, cb->user_data); setup_cb_free(cb); } return FALSE; } static gboolean finalize_resume(gpointer data) { struct a2dp_setup *s = data; GSList *l; for (l = s->cb; l != NULL; ) { struct a2dp_setup_cb *cb = l->data; l = l->next; if (!cb->resume_cb) continue; cb->resume_cb(s->session, s->err, cb->user_data); setup_cb_free(cb); } return FALSE; } static gboolean finalize_suspend(gpointer data) { struct a2dp_setup *s = data; GSList *l; for (l = s->cb; l != NULL; ) { struct a2dp_setup_cb *cb = l->data; l = l->next; if (!cb->suspend_cb) continue; cb->suspend_cb(s->session, s->err, cb->user_data); setup_cb_free(cb); } return FALSE; } static void finalize_select(struct a2dp_setup *s) { GSList *l; for (l = s->cb; l != NULL; ) { struct a2dp_setup_cb *cb = l->data; l = l->next; if (!cb->select_cb) continue; cb->select_cb(s->session, s->sep, s->caps, cb->user_data); setup_cb_free(cb); } } static struct a2dp_setup *find_setup_by_session(struct avdtp *session) { GSList *l; for (l = setups; l != NULL; l = l->next) { struct a2dp_setup *setup = l->data; if (setup->session == session) return setup; } return NULL; } static struct a2dp_setup *a2dp_setup_get(struct avdtp *session) { struct a2dp_setup *setup; setup = find_setup_by_session(session); if (!setup) { setup = setup_new(session); if (!setup) return NULL; } return setup_ref(setup); } static struct a2dp_setup *find_setup_by_dev(struct audio_device *dev) { GSList *l; for (l = setups; l != NULL; l = l->next) { struct a2dp_setup *setup = l->data; if (setup->dev == dev) return setup; } return NULL; } 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 a2dp_sep *sep = user_data; if (new_state != AVDTP_STATE_IDLE) return; if (sep->suspend_timer) { g_source_remove(sep->suspend_timer); sep->suspend_timer = 0; } if (sep->session) { avdtp_unref(sep->session); sep->session = NULL; } sep->stream = NULL; if (sep->endpoint && sep->endpoint->clear_configuration) sep->endpoint->clear_configuration(sep, sep->user_data); } static gboolean auto_config(gpointer data) { struct a2dp_setup *setup = data; struct avdtp_error *err = NULL; /* Check if configuration was aborted */ if (setup->sep->stream == NULL) return FALSE; if (setup->err != NULL) { err = setup->err; goto done; } avdtp_stream_add_cb(setup->session, setup->stream, stream_state_changed, setup->sep); if (setup->sep->type == AVDTP_SEP_TYPE_SOURCE) sink_new_stream(setup->dev, setup->session, setup->stream); else source_new_stream(setup->dev, setup->session, setup->stream); done: if (setup->setconf_cb) setup->setconf_cb(setup->session, setup->stream, setup->err); finalize_config(setup); if (err) g_free(err); setup_unref(setup); return FALSE; } static gboolean sbc_setconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, GSList *caps, avdtp_set_configuration_cb cb, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Set_Configuration_Ind", sep); else DBG("Source %p: Set_Configuration_Ind", sep); setup = a2dp_setup_get(session); if (!setup) return FALSE; a2dp_sep->stream = stream; setup->sep = a2dp_sep; setup->stream = stream; setup->setconf_cb = cb; /* Check valid settings */ for (; caps != NULL; caps = g_slist_next(caps)) { struct avdtp_service_capability *cap = caps->data; struct avdtp_media_codec_capability *codec_cap; struct sbc_codec_cap *sbc_cap; if (cap->category == AVDTP_DELAY_REPORTING && !a2dp_sep->delay_reporting) { setup->err = g_new(struct avdtp_error, 1); avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING, AVDTP_UNSUPPORTED_CONFIGURATION); goto done; } if (cap->category != AVDTP_MEDIA_CODEC) continue; if (cap->length < sizeof(struct sbc_codec_cap)) continue; codec_cap = (void *) cap->data; if (codec_cap->media_codec_type != A2DP_CODEC_SBC) continue; sbc_cap = (void *) codec_cap; if (sbc_cap->min_bitpool < MIN_BITPOOL || sbc_cap->max_bitpool > MAX_BITPOOL) { setup->err = g_new(struct avdtp_error, 1); avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC, AVDTP_UNSUPPORTED_CONFIGURATION); goto done; } } done: g_idle_add(auto_config, setup); return TRUE; } static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep, gboolean get_all, GSList **caps, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct avdtp_service_capability *media_transport, *media_codec; struct sbc_codec_cap sbc_cap; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Get_Capability_Ind", sep); else DBG("Source %p: Get_Capability_Ind", sep); *caps = NULL; media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0); *caps = g_slist_append(*caps, media_transport); memset(&sbc_cap, 0, sizeof(struct sbc_codec_cap)); sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO; sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC; sbc_cap.frequency = ( SBC_SAMPLING_FREQ_48000 | SBC_SAMPLING_FREQ_44100 | SBC_SAMPLING_FREQ_32000 | SBC_SAMPLING_FREQ_16000 ); sbc_cap.channel_mode = ( SBC_CHANNEL_MODE_JOINT_STEREO | SBC_CHANNEL_MODE_STEREO | SBC_CHANNEL_MODE_DUAL_CHANNEL | SBC_CHANNEL_MODE_MONO ); sbc_cap.block_length = ( SBC_BLOCK_LENGTH_16 | SBC_BLOCK_LENGTH_12 | SBC_BLOCK_LENGTH_8 | SBC_BLOCK_LENGTH_4 ); sbc_cap.subbands = ( SBC_SUBBANDS_8 | SBC_SUBBANDS_4 ); sbc_cap.allocation_method = ( SBC_ALLOCATION_LOUDNESS | SBC_ALLOCATION_SNR ); sbc_cap.min_bitpool = MIN_BITPOOL; sbc_cap.max_bitpool = MAX_BITPOOL; media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap, sizeof(sbc_cap)); *caps = g_slist_append(*caps, media_codec); if (get_all) { struct avdtp_service_capability *delay_reporting; delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING, NULL, 0); *caps = g_slist_append(*caps, delay_reporting); } return TRUE; } static gboolean mpeg_setconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, GSList *caps, avdtp_set_configuration_cb cb, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Set_Configuration_Ind", sep); else DBG("Source %p: Set_Configuration_Ind", sep); setup = a2dp_setup_get(session); if (!setup) return FALSE; a2dp_sep->stream = stream; setup->sep = a2dp_sep; setup->stream = stream; setup->setconf_cb = cb; for (; caps != NULL; caps = g_slist_next(caps)) { struct avdtp_service_capability *cap = caps->data; if (cap->category == AVDTP_DELAY_REPORTING && !a2dp_sep->delay_reporting) { setup->err = g_new(struct avdtp_error, 1); avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING, AVDTP_UNSUPPORTED_CONFIGURATION); goto done; } } done: g_idle_add(auto_config, setup); return TRUE; } static gboolean mpeg_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep, gboolean get_all, GSList **caps, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct avdtp_service_capability *media_transport, *media_codec; struct mpeg_codec_cap mpeg_cap; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Get_Capability_Ind", sep); else DBG("Source %p: Get_Capability_Ind", sep); *caps = NULL; media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0); *caps = g_slist_append(*caps, media_transport); memset(&mpeg_cap, 0, sizeof(struct mpeg_codec_cap)); mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO; mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12; mpeg_cap.frequency = ( MPEG_SAMPLING_FREQ_48000 | MPEG_SAMPLING_FREQ_44100 | MPEG_SAMPLING_FREQ_32000 | MPEG_SAMPLING_FREQ_24000 | MPEG_SAMPLING_FREQ_22050 | MPEG_SAMPLING_FREQ_16000 ); mpeg_cap.channel_mode = ( MPEG_CHANNEL_MODE_JOINT_STEREO | MPEG_CHANNEL_MODE_STEREO | MPEG_CHANNEL_MODE_DUAL_CHANNEL | MPEG_CHANNEL_MODE_MONO ); mpeg_cap.layer = ( MPEG_LAYER_MP3 | MPEG_LAYER_MP2 | MPEG_LAYER_MP1 ); mpeg_cap.bitrate = 0xFFFF; media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap, sizeof(mpeg_cap)); *caps = g_slist_append(*caps, media_codec); if (get_all) { struct avdtp_service_capability *delay_reporting; delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING, NULL, 0); *caps = g_slist_append(*caps, delay_reporting); } return TRUE; } static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret) { if (ret == FALSE) { setup->err = g_new(struct avdtp_error, 1); avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC, AVDTP_UNSUPPORTED_CONFIGURATION); } auto_config(setup); } static gboolean endpoint_setconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, GSList *caps, avdtp_set_configuration_cb cb, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Set_Configuration_Ind", sep); else DBG("Source %p: Set_Configuration_Ind", sep); setup = a2dp_setup_get(session); if (!session) return FALSE; a2dp_sep->stream = stream; setup->sep = a2dp_sep; setup->stream = stream; setup->setconf_cb = cb; for (; caps != NULL; caps = g_slist_next(caps)) { struct avdtp_service_capability *cap = caps->data; struct avdtp_media_codec_capability *codec; gboolean ret; if (cap->category == AVDTP_DELAY_REPORTING && !a2dp_sep->delay_reporting) { setup->err = g_new(struct avdtp_error, 1); avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING, AVDTP_UNSUPPORTED_CONFIGURATION); goto done; } if (cap->category != AVDTP_MEDIA_CODEC) continue; codec = (struct avdtp_media_codec_capability *) cap->data; if (codec->media_codec_type != a2dp_sep->codec) { setup->err = g_new(struct avdtp_error, 1); avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC, AVDTP_UNSUPPORTED_CONFIGURATION); goto done; } ret = a2dp_sep->endpoint->set_configuration(a2dp_sep, setup->dev, codec->data, cap->length - sizeof(*codec), setup, endpoint_setconf_cb, a2dp_sep->user_data); if (ret == 0) return TRUE; setup->err = g_new(struct avdtp_error, 1); avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC, AVDTP_UNSUPPORTED_CONFIGURATION); break; } done: g_idle_add(auto_config, setup); return TRUE; } static gboolean endpoint_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep, gboolean get_all, GSList **caps, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct avdtp_service_capability *media_transport, *media_codec; struct avdtp_media_codec_capability *codec_caps; uint8_t *capabilities; size_t length; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Get_Capability_Ind", sep); else DBG("Source %p: Get_Capability_Ind", sep); *caps = NULL; media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0); *caps = g_slist_append(*caps, media_transport); length = a2dp_sep->endpoint->get_capabilities(a2dp_sep, &capabilities, a2dp_sep->user_data); codec_caps = g_malloc0(sizeof(*codec_caps) + length); codec_caps->media_type = AVDTP_MEDIA_TYPE_AUDIO; codec_caps->media_codec_type = a2dp_sep->codec; memcpy(codec_caps->data, capabilities, length); media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec_caps, sizeof(*codec_caps) + length); *caps = g_slist_append(*caps, media_codec); g_free(codec_caps); if (get_all) { struct avdtp_service_capability *delay_reporting; delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING, NULL, 0); *caps = g_slist_append(*caps, delay_reporting); } return TRUE; } static void endpoint_open_cb(struct a2dp_setup *setup, gboolean ret) { int err; if (ret == FALSE) { setup->stream = NULL; finalize_setup_errno(setup, -EPERM, finalize_config, NULL); return; } err = avdtp_open(setup->session, setup->stream); if (err == 0) return; error("Error on avdtp_open %s (%d)", strerror(-err), -err); setup->stream = NULL; finalize_setup_errno(setup, err, finalize_config, NULL); } static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; struct audio_device *dev; int ret; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Set_Configuration_Cfm", sep); else DBG("Source %p: Set_Configuration_Cfm", sep); setup = find_setup_by_session(session); if (err) { if (setup) { setup->err = err; finalize_config(setup); } return; } avdtp_stream_add_cb(session, stream, stream_state_changed, a2dp_sep); a2dp_sep->stream = stream; if (!setup) return; dev = a2dp_get_dev(session); /* Notify D-Bus interface of the new stream */ if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE) sink_new_stream(dev, session, setup->stream); else source_new_stream(dev, session, setup->stream); /* Notify Endpoint */ if (a2dp_sep->endpoint) { struct avdtp_service_capability *service; struct avdtp_media_codec_capability *codec; int err; service = avdtp_stream_get_codec(stream); codec = (struct avdtp_media_codec_capability *) service->data; err = a2dp_sep->endpoint->set_configuration(a2dp_sep, dev, codec->data, service->length - sizeof(*codec), setup, endpoint_open_cb, a2dp_sep->user_data); if (err == 0) return; setup->stream = NULL; finalize_setup_errno(setup, -EPERM, finalize_config, NULL); return; } ret = avdtp_open(session, stream); if (ret < 0) { error("Error on avdtp_open %s (%d)", strerror(-ret), -ret); setup->stream = NULL; finalize_setup_errno(setup, ret, finalize_config, NULL); } } static gboolean getconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Get_Configuration_Ind", sep); else DBG("Source %p: Get_Configuration_Ind", sep); return TRUE; } static void getconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Set_Configuration_Cfm", sep); else DBG("Source %p: Set_Configuration_Cfm", sep); } static gboolean open_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Open_Ind", sep); else DBG("Source %p: Open_Ind", sep); setup = find_setup_by_session(session); if (!setup) return TRUE; if (setup->reconfigure) setup->reconfigure = FALSE; finalize_config(setup); return TRUE; } static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Open_Cfm", sep); else DBG("Source %p: Open_Cfm", sep); setup = find_setup_by_session(session); if (!setup) return; if (setup->reconfigure) setup->reconfigure = FALSE; if (err) { setup->stream = NULL; setup->err = err; } finalize_config(setup); } static gboolean suspend_timeout(struct a2dp_sep *sep) { if (avdtp_suspend(sep->session, sep->stream) == 0) sep->suspending = TRUE; sep->suspend_timer = 0; avdtp_unref(sep->session); sep->session = NULL; return FALSE; } static gboolean start_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Start_Ind", sep); else DBG("Source %p: Start_Ind", sep); if (!a2dp_sep->locked) { a2dp_sep->session = avdtp_ref(session); a2dp_sep->suspend_timer = g_timeout_add_seconds(SUSPEND_TIMEOUT, (GSourceFunc) suspend_timeout, a2dp_sep); } if (!a2dp_sep->starting) return TRUE; a2dp_sep->starting = FALSE; setup = find_setup_by_session(session); if (setup) finalize_resume(setup); return TRUE; } static void start_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Start_Cfm", sep); else DBG("Source %p: Start_Cfm", sep); a2dp_sep->starting = FALSE; setup = find_setup_by_session(session); if (!setup) return; if (err) { setup->stream = NULL; setup->err = err; } finalize_resume(setup); } static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; gboolean start; int start_err; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Suspend_Ind", sep); else DBG("Source %p: Suspend_Ind", sep); if (a2dp_sep->suspend_timer) { g_source_remove(a2dp_sep->suspend_timer); a2dp_sep->suspend_timer = 0; avdtp_unref(a2dp_sep->session); a2dp_sep->session = NULL; } if (!a2dp_sep->suspending) return TRUE; a2dp_sep->suspending = FALSE; setup = find_setup_by_session(session); if (!setup) return TRUE; start = setup->start; setup->start = FALSE; finalize_suspend(setup); if (!start) return TRUE; start_err = avdtp_start(session, a2dp_sep->stream); if (start_err < 0 && start_err != -EINPROGRESS) { error("avdtp_start: %s (%d)", strerror(-start_err), -start_err); finalize_setup_errno(setup, start_err, finalize_resume); } return TRUE; } static void suspend_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; gboolean start; int start_err; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Suspend_Cfm", sep); else DBG("Source %p: Suspend_Cfm", sep); a2dp_sep->suspending = FALSE; setup = find_setup_by_session(session); if (!setup) return; start = setup->start; setup->start = FALSE; if (err) { setup->stream = NULL; setup->err = err; } finalize_suspend(setup); if (!start) return; if (err) { finalize_resume(setup); return; } start_err = avdtp_start(session, a2dp_sep->stream); if (start_err < 0 && start_err != -EINPROGRESS) { error("avdtp_start: %s (%d)", strerror(-start_err), -start_err); finalize_setup_errno(setup, start_err, finalize_suspend, NULL); } } static gboolean close_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Close_Ind", sep); else DBG("Source %p: Close_Ind", sep); setup = find_setup_by_session(session); if (!setup) return TRUE; finalize_setup_errno(setup, -ECONNRESET, finalize_suspend, finalize_resume, NULL); return TRUE; } static gboolean a2dp_reconfigure(gpointer data) { struct a2dp_setup *setup = data; struct a2dp_sep *sep = setup->sep; int posix_err; struct avdtp_media_codec_capability *rsep_codec; struct avdtp_service_capability *cap; if (setup->rsep) { cap = avdtp_get_codec(setup->rsep); rsep_codec = (struct avdtp_media_codec_capability *) cap->data; } if (!setup->rsep || sep->codec != rsep_codec->media_codec_type) setup->rsep = avdtp_find_remote_sep(setup->session, sep->lsep); posix_err = avdtp_set_configuration(setup->session, setup->rsep, sep->lsep, setup->caps, &setup->stream); if (posix_err < 0) { error("avdtp_set_configuration: %s", strerror(-posix_err)); goto failed; } return FALSE; failed: finalize_setup_errno(setup, posix_err, finalize_config, NULL); return FALSE; } static void close_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Close_Cfm", sep); else DBG("Source %p: Close_Cfm", sep); setup = find_setup_by_session(session); if (!setup) return; if (err) { setup->stream = NULL; setup->err = err; finalize_config(setup); return; } if (!setup->rsep) setup->rsep = avdtp_stream_get_remote_sep(stream); if (setup->reconfigure) g_timeout_add(RECONFIGURE_TIMEOUT, a2dp_reconfigure, setup); } static void abort_ind(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Abort_Ind", sep); else DBG("Source %p: Abort_Ind", sep); a2dp_sep->stream = NULL; setup = find_setup_by_session(session); if (!setup) return; finalize_setup_errno(setup, -ECONNRESET, finalize_suspend, finalize_resume, finalize_config); return; } static void abort_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: Abort_Cfm", sep); else DBG("Source %p: Abort_Cfm", sep); setup = find_setup_by_session(session); if (!setup) return; setup_unref(setup); } static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: ReConfigure_Ind", sep); else DBG("Source %p: ReConfigure_Ind", sep); return TRUE; } static gboolean delayreport_ind(struct avdtp *session, struct avdtp_local_sep *sep, uint8_t rseid, uint16_t delay, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct audio_device *dev = a2dp_get_dev(session); if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: DelayReport_Ind", sep); else DBG("Source %p: DelayReport_Ind", sep); unix_delay_report(dev, rseid, delay); return TRUE; } static gboolean endpoint_delayreport_ind(struct avdtp *session, struct avdtp_local_sep *sep, uint8_t rseid, uint16_t delay, uint8_t *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: DelayReport_Ind", sep); else DBG("Source %p: DelayReport_Ind", sep); if (a2dp_sep->endpoint == NULL || a2dp_sep->endpoint->set_delay == NULL) return FALSE; a2dp_sep->endpoint->set_delay(a2dp_sep, delay, a2dp_sep->user_data); return TRUE; } static void reconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; struct a2dp_setup *setup; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: ReConfigure_Cfm", sep); else DBG("Source %p: ReConfigure_Cfm", sep); setup = find_setup_by_session(session); if (!setup) return; if (err) { setup->stream = NULL; setup->err = err; } finalize_config(setup); } static void delay_report_cfm(struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct a2dp_sep *a2dp_sep = user_data; if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK) DBG("Sink %p: DelayReport_Cfm", sep); else DBG("Source %p: DelayReport_Cfm", sep); } static struct avdtp_sep_cfm cfm = { .set_configuration = setconf_cfm, .get_configuration = getconf_cfm, .open = open_cfm, .start = start_cfm, .suspend = suspend_cfm, .close = close_cfm, .abort = abort_cfm, .reconfigure = reconf_cfm, .delay_report = delay_report_cfm, }; static struct avdtp_sep_ind sbc_ind = { .get_capability = sbc_getcap_ind, .set_configuration = sbc_setconf_ind, .get_configuration = getconf_ind, .open = open_ind, .start = start_ind, .suspend = suspend_ind, .close = close_ind, .abort = abort_ind, .reconfigure = reconf_ind, .delayreport = delayreport_ind, }; static struct avdtp_sep_ind mpeg_ind = { .get_capability = mpeg_getcap_ind, .set_configuration = mpeg_setconf_ind, .get_configuration = getconf_ind, .open = open_ind, .start = start_ind, .suspend = suspend_ind, .close = close_ind, .abort = abort_ind, .reconfigure = reconf_ind, .delayreport = delayreport_ind, }; static struct avdtp_sep_ind endpoint_ind = { .get_capability = endpoint_getcap_ind, .set_configuration = endpoint_setconf_ind, .get_configuration = getconf_ind, .open = open_ind, .start = start_ind, .suspend = suspend_ind, .close = close_ind, .abort = abort_ind, .reconfigure = reconf_ind, .delayreport = endpoint_delayreport_ind, }; static sdp_record_t *a2dp_record(uint8_t type, uint16_t avdtp_ver) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, l2cap_uuid, avdtp_uuid, a2dp_uuid; sdp_profile_desc_t profile[1]; sdp_list_t *aproto, *proto[2]; sdp_record_t *record; sdp_data_t *psm, *version, *features; uint16_t lp = AVDTP_UUID; uint16_t a2dp_ver = 0x0102, feat = 0x000f; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(record, root); if (type == AVDTP_SEP_TYPE_SOURCE) sdp_uuid16_create(&a2dp_uuid, AUDIO_SOURCE_SVCLASS_ID); else sdp_uuid16_create(&a2dp_uuid, AUDIO_SINK_SVCLASS_ID); svclass_id = sdp_list_append(0, &a2dp_uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID); profile[0].version = a2dp_ver; pfseq = sdp_list_append(0, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap_uuid); psm = sdp_data_alloc(SDP_UINT16, &lp); proto[0] = sdp_list_append(proto[0], psm); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID); proto[1] = sdp_list_append(0, &avdtp_uuid); version = sdp_data_alloc(SDP_UINT16, &avdtp_ver); proto[1] = sdp_list_append(proto[1], version); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(record, aproto); features = sdp_data_alloc(SDP_UINT16, &feat); sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features); if (type == AVDTP_SEP_TYPE_SOURCE) sdp_set_info_attr(record, "Audio Source", 0, 0); else sdp_set_info_attr(record, "Audio Sink", 0, 0); free(psm); free(version); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(pfseq, 0); sdp_list_free(aproto, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); return record; } static struct a2dp_server *find_server(GSList *list, const bdaddr_t *src) { for (; list; list = list->next) { struct a2dp_server *server = list->data; if (bacmp(&server->src, src) == 0) return server; } return NULL; } int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config) { int sbc_srcs = 0, sbc_sinks = 0; int mpeg12_srcs = 0, mpeg12_sinks = 0; gboolean source = TRUE, sink = FALSE, socket = FALSE; gboolean delay_reporting = FALSE; char *str; GError *err = NULL; int i; struct a2dp_server *server; if (!config) goto proceed; str = g_key_file_get_string(config, "General", "Enable", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else { if (strstr(str, "Sink")) source = TRUE; if (strstr(str, "Source")) sink = TRUE; if (strstr(str, "Socket")) socket = TRUE; g_free(str); } str = g_key_file_get_string(config, "General", "Disable", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else { if (strstr(str, "Sink")) source = FALSE; if (strstr(str, "Source")) sink = FALSE; if (strstr(str, "Socket")) socket = FALSE; g_free(str); } /* Don't register any local sep if Socket is disabled */ if (socket == FALSE) goto proceed; str = g_key_file_get_string(config, "A2DP", "SBCSources", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); sbc_srcs = 1; } else { sbc_srcs = atoi(str); g_free(str); } str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else { mpeg12_srcs = atoi(str); g_free(str); } str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); sbc_sinks = 1; } else { sbc_sinks = atoi(str); g_free(str); } str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else { mpeg12_sinks = atoi(str); g_free(str); } proceed: if (!connection) connection = dbus_connection_ref(conn); server = find_server(servers, src); if (!server) { int av_err; server = g_new0(struct a2dp_server, 1); if (!server) return -ENOMEM; av_err = avdtp_init(src, config, &server->version); if (av_err < 0) { g_free(server); return av_err; } bacpy(&server->src, src); servers = g_slist_append(servers, server); } if (config) delay_reporting = g_key_file_get_boolean(config, "A2DP", "DelayReporting", NULL); if (delay_reporting) server->version = 0x0103; else server->version = 0x0102; server->source_enabled = source; if (source) { for (i = 0; i < sbc_srcs; i++) a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE, A2DP_CODEC_SBC, delay_reporting, NULL, NULL, NULL, NULL); for (i = 0; i < mpeg12_srcs; i++) a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE, A2DP_CODEC_MPEG12, delay_reporting, NULL, NULL, NULL, NULL); } server->sink_enabled = sink; if (sink) { for (i = 0; i < sbc_sinks; i++) a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK, A2DP_CODEC_SBC, delay_reporting, NULL, NULL, NULL, NULL); for (i = 0; i < mpeg12_sinks; i++) a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK, A2DP_CODEC_MPEG12, delay_reporting, NULL, NULL, NULL, NULL); } return 0; } static void a2dp_unregister_sep(struct a2dp_sep *sep) { if (sep->destroy) { sep->destroy(sep->user_data); sep->endpoint = NULL; } avdtp_unregister_sep(sep->lsep); g_free(sep); } void a2dp_unregister(const bdaddr_t *src) { struct a2dp_server *server; server = find_server(servers, src); if (!server) return; g_slist_free_full(server->sinks, (GDestroyNotify) a2dp_unregister_sep); g_slist_free_full(server->sources, (GDestroyNotify) a2dp_unregister_sep); avdtp_exit(src); servers = g_slist_remove(servers, server); if (server->source_record_id) remove_record_from_server(server->source_record_id); if (server->sink_record_id) remove_record_from_server(server->sink_record_id); g_free(server); if (servers) return; dbus_connection_unref(connection); connection = NULL; } struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type, uint8_t codec, gboolean delay_reporting, struct a2dp_endpoint *endpoint, void *user_data, GDestroyNotify destroy, int *err) { struct a2dp_server *server; struct a2dp_sep *sep; GSList **l; uint32_t *record_id; sdp_record_t *record; struct avdtp_sep_ind *ind; server = find_server(servers, src); if (server == NULL) { if (err) *err = -EPROTONOSUPPORT; return NULL; } if (type == AVDTP_SEP_TYPE_SINK && !server->sink_enabled) { if (err) *err = -EPROTONOSUPPORT; return NULL; } if (type == AVDTP_SEP_TYPE_SOURCE && !server->source_enabled) { if (err) *err = -EPROTONOSUPPORT; return NULL; } sep = g_new0(struct a2dp_sep, 1); if (endpoint) { ind = &endpoint_ind; goto proceed; } ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind; proceed: sep->lsep = avdtp_register_sep(&server->src, type, AVDTP_MEDIA_TYPE_AUDIO, codec, delay_reporting, ind, &cfm, sep); if (sep->lsep == NULL) { g_free(sep); if (err) *err = -EINVAL; return NULL; } sep->server = server; sep->endpoint = endpoint; sep->codec = codec; sep->type = type; sep->delay_reporting = delay_reporting; sep->user_data = user_data; sep->destroy = destroy; if (type == AVDTP_SEP_TYPE_SOURCE) { l = &server->sources; record_id = &server->source_record_id; } else { l = &server->sinks; record_id = &server->sink_record_id; } if (*record_id != 0) goto add; record = a2dp_record(type, server->version); if (!record) { error("Unable to allocate new service record"); avdtp_unregister_sep(sep->lsep); g_free(sep); if (err) *err = -EINVAL; return NULL; } if (add_record_to_server(&server->src, record) < 0) { error("Unable to register A2DP service record");\ sdp_record_free(record); avdtp_unregister_sep(sep->lsep); g_free(sep); if (err) *err = -EINVAL; return NULL; } *record_id = record->handle; add: *l = g_slist_append(*l, sep); if (err) *err = 0; return sep; } void a2dp_remove_sep(struct a2dp_sep *sep) { struct a2dp_server *server = sep->server; if (sep->type == AVDTP_SEP_TYPE_SOURCE) { if (g_slist_find(server->sources, sep) == NULL) return; server->sources = g_slist_remove(server->sources, sep); if (server->sources == NULL && server->source_record_id) { remove_record_from_server(server->source_record_id); server->source_record_id = 0; } } else { if (g_slist_find(server->sinks, sep) == NULL) return; server->sinks = g_slist_remove(server->sinks, sep); if (server->sinks == NULL && server->sink_record_id) { remove_record_from_server(server->sink_record_id); server->sink_record_id = 0; } } if (sep->locked) return; a2dp_unregister_sep(sep); } struct a2dp_sep *a2dp_get(struct avdtp *session, struct avdtp_remote_sep *rsep) { GSList *l; struct a2dp_server *server; struct avdtp_service_capability *cap; struct avdtp_media_codec_capability *codec_cap = NULL; bdaddr_t src; avdtp_get_peers(session, &src, NULL); server = find_server(servers, &src); if (!server) return NULL; cap = avdtp_get_codec(rsep); codec_cap = (void *) cap->data; if (avdtp_get_type(rsep) == AVDTP_SEP_TYPE_SINK) l = server->sources; else l = server->sinks; for (; l != NULL; l = l->next) { struct a2dp_sep *sep = l->data; if (sep->locked) continue; if (sep->codec != codec_cap->media_codec_type) continue; if (!sep->stream || avdtp_has_stream(session, sep->stream)) return sep; } return NULL; } static uint8_t default_bitpool(uint8_t freq, uint8_t mode) { switch (freq) { case SBC_SAMPLING_FREQ_16000: case SBC_SAMPLING_FREQ_32000: return 53; case SBC_SAMPLING_FREQ_44100: switch (mode) { case SBC_CHANNEL_MODE_MONO: case SBC_CHANNEL_MODE_DUAL_CHANNEL: return 31; case SBC_CHANNEL_MODE_STEREO: case SBC_CHANNEL_MODE_JOINT_STEREO: return 53; default: error("Invalid channel mode %u", mode); return 53; } case SBC_SAMPLING_FREQ_48000: switch (mode) { case SBC_CHANNEL_MODE_MONO: case SBC_CHANNEL_MODE_DUAL_CHANNEL: return 29; case SBC_CHANNEL_MODE_STEREO: case SBC_CHANNEL_MODE_JOINT_STEREO: return 51; default: error("Invalid channel mode %u", mode); return 51; } default: error("Invalid sampling freq %u", freq); return 53; } } static gboolean select_sbc_params(struct sbc_codec_cap *cap, struct sbc_codec_cap *supported) { unsigned int max_bitpool, min_bitpool; memset(cap, 0, sizeof(struct sbc_codec_cap)); cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO; cap->cap.media_codec_type = A2DP_CODEC_SBC; if (supported->frequency & SBC_SAMPLING_FREQ_44100) cap->frequency = SBC_SAMPLING_FREQ_44100; else if (supported->frequency & SBC_SAMPLING_FREQ_48000) cap->frequency = SBC_SAMPLING_FREQ_48000; else if (supported->frequency & SBC_SAMPLING_FREQ_32000) cap->frequency = SBC_SAMPLING_FREQ_32000; else if (supported->frequency & SBC_SAMPLING_FREQ_16000) cap->frequency = SBC_SAMPLING_FREQ_16000; else { error("No supported frequencies"); return FALSE; } if (supported->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO) cap->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO; else if (supported->channel_mode & SBC_CHANNEL_MODE_STEREO) cap->channel_mode = SBC_CHANNEL_MODE_STEREO; else if (supported->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL) cap->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL; else if (supported->channel_mode & SBC_CHANNEL_MODE_MONO) cap->channel_mode = SBC_CHANNEL_MODE_MONO; else { error("No supported channel modes"); return FALSE; } if (supported->block_length & SBC_BLOCK_LENGTH_16) cap->block_length = SBC_BLOCK_LENGTH_16; else if (supported->block_length & SBC_BLOCK_LENGTH_12) cap->block_length = SBC_BLOCK_LENGTH_12; else if (supported->block_length & SBC_BLOCK_LENGTH_8) cap->block_length = SBC_BLOCK_LENGTH_8; else if (supported->block_length & SBC_BLOCK_LENGTH_4) cap->block_length = SBC_BLOCK_LENGTH_4; else { error("No supported block lengths"); return FALSE; } if (supported->subbands & SBC_SUBBANDS_8) cap->subbands = SBC_SUBBANDS_8; else if (supported->subbands & SBC_SUBBANDS_4) cap->subbands = SBC_SUBBANDS_4; else { error("No supported subbands"); return FALSE; } if (supported->allocation_method & SBC_ALLOCATION_LOUDNESS) cap->allocation_method = SBC_ALLOCATION_LOUDNESS; else if (supported->allocation_method & SBC_ALLOCATION_SNR) cap->allocation_method = SBC_ALLOCATION_SNR; min_bitpool = MAX(MIN_BITPOOL, supported->min_bitpool); max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode), supported->max_bitpool); cap->min_bitpool = min_bitpool; cap->max_bitpool = max_bitpool; return TRUE; } static gboolean select_capabilities(struct avdtp *session, struct avdtp_remote_sep *rsep, GSList **caps) { struct avdtp_service_capability *media_transport, *media_codec; struct sbc_codec_cap sbc_cap; media_codec = avdtp_get_codec(rsep); if (!media_codec) return FALSE; select_sbc_params(&sbc_cap, (struct sbc_codec_cap *) media_codec->data); media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0); *caps = g_slist_append(*caps, media_transport); media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap, sizeof(sbc_cap)); *caps = g_slist_append(*caps, media_codec); if (avdtp_get_delay_reporting(rsep)) { struct avdtp_service_capability *delay_reporting; delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING, NULL, 0); *caps = g_slist_append(*caps, delay_reporting); } return TRUE; } static void select_cb(struct a2dp_setup *setup, void *ret, int size) { struct avdtp_service_capability *media_transport, *media_codec; struct avdtp_media_codec_capability *cap; if (size < 0) { DBG("Endpoint replied an invalid configuration"); goto done; } media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT, NULL, 0); setup->caps = g_slist_append(setup->caps, media_transport); cap = g_malloc0(sizeof(*cap) + size); cap->media_type = AVDTP_MEDIA_TYPE_AUDIO; cap->media_codec_type = setup->sep->codec; memcpy(cap->data, ret, size); media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, cap, sizeof(*cap) + size); setup->caps = g_slist_append(setup->caps, media_codec); g_free(cap); done: finalize_select(setup); } static gboolean auto_select(gpointer data) { struct a2dp_setup *setup = data; finalize_select(setup); return FALSE; } static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list, const char *sender) { for (; list; list = list->next) { struct a2dp_sep *sep = list->data; /* Use sender's endpoint if available */ if (sender) { const char *name; if (sep->endpoint == NULL) continue; name = sep->endpoint->get_name(sep, sep->user_data); if (g_strcmp0(sender, name) != 0) continue; } if (avdtp_find_remote_sep(session, sep->lsep) == NULL) continue; return sep; } return NULL; } static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type, const char *sender) { struct a2dp_server *server; struct a2dp_sep *sep; GSList *l; bdaddr_t src; avdtp_get_peers(session, &src, NULL); server = find_server(servers, &src); if (!server) return NULL; l = type == AVDTP_SEP_TYPE_SINK ? server->sources : server->sinks; /* Check sender's seps first */ sep = a2dp_find_sep(session, l, sender); if (sep != NULL) return sep; return a2dp_find_sep(session, l, NULL); } unsigned int a2dp_select_capabilities(struct avdtp *session, uint8_t type, const char *sender, a2dp_select_cb_t cb, void *user_data) { struct a2dp_setup *setup; struct a2dp_setup_cb *cb_data; struct a2dp_sep *sep; struct avdtp_service_capability *service; struct avdtp_media_codec_capability *codec; int err; sep = a2dp_select_sep(session, type, sender); if (!sep) { error("Unable to select SEP"); return 0; } setup = a2dp_setup_get(session); if (!setup) return 0; cb_data = setup_cb_new(setup); cb_data->select_cb = cb; cb_data->user_data = user_data; setup->sep = sep; setup->rsep = avdtp_find_remote_sep(session, sep->lsep); if (setup->rsep == NULL) { error("Could not find remote sep"); goto fail; } /* FIXME: Remove auto select when it is not longer possible to register endpoint in the configuration file */ if (sep->endpoint == NULL) { if (!select_capabilities(session, setup->rsep, &setup->caps)) { error("Unable to auto select remote SEP capabilities"); goto fail; } g_idle_add(auto_select, setup); return cb_data->id; } service = avdtp_get_codec(setup->rsep); codec = (struct avdtp_media_codec_capability *) service->data; err = sep->endpoint->select_configuration(sep, codec->data, service->length - sizeof(*codec), setup, select_cb, sep->user_data); if (err == 0) return cb_data->id; fail: setup_cb_free(cb_data); return 0; } unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep, a2dp_config_cb_t cb, GSList *caps, void *user_data) { struct a2dp_setup_cb *cb_data; GSList *l; struct a2dp_server *server; struct a2dp_setup *setup; struct a2dp_sep *tmp; struct avdtp_service_capability *cap; struct avdtp_media_codec_capability *codec_cap = NULL; int posix_err; bdaddr_t src; avdtp_get_peers(session, &src, NULL); server = find_server(servers, &src); if (!server) return 0; for (l = caps; l != NULL; l = l->next) { cap = l->data; if (cap->category != AVDTP_MEDIA_CODEC) continue; codec_cap = (void *) cap->data; break; } if (!codec_cap) return 0; if (sep->codec != codec_cap->media_codec_type) return 0; DBG("a2dp_config: selected SEP %p", sep->lsep); setup = a2dp_setup_get(session); if (!setup) return 0; cb_data = setup_cb_new(setup); cb_data->config_cb = cb; cb_data->user_data = user_data; setup->sep = sep; setup->stream = sep->stream; /* Copy given caps if they are different than current caps */ if (setup->caps != caps) { g_slist_free_full(setup->caps, g_free); setup->caps = g_slist_copy(caps); } switch (avdtp_sep_get_state(sep->lsep)) { case AVDTP_STATE_IDLE: if (sep->type == AVDTP_SEP_TYPE_SOURCE) l = server->sources; else l = server->sinks; for (; l != NULL; l = l->next) { tmp = l->data; if (avdtp_has_stream(session, tmp->stream)) break; } if (l != NULL) { if (a2dp_sep_get_lock(tmp)) goto failed; setup->reconfigure = TRUE; if (avdtp_close(session, tmp->stream, FALSE) < 0) { error("avdtp_close failed"); goto failed; } break; } setup->rsep = avdtp_find_remote_sep(session, sep->lsep); if (setup->rsep == NULL) { error("No matching ACP and INT SEPs found"); goto failed; } posix_err = avdtp_set_configuration(session, setup->rsep, sep->lsep, caps, &setup->stream); if (posix_err < 0) { error("avdtp_set_configuration: %s", strerror(-posix_err)); goto failed; } break; case AVDTP_STATE_OPEN: case AVDTP_STATE_STREAMING: if (avdtp_stream_has_capabilities(setup->stream, caps)) { DBG("Configuration match: resuming"); cb_data->source_id = g_idle_add(finalize_config, setup); } else if (!setup->reconfigure) { setup->reconfigure = TRUE; if (avdtp_close(session, sep->stream, FALSE) < 0) { error("avdtp_close failed"); goto failed; } } break; default: error("SEP in bad state for requesting a new stream"); goto failed; } return cb_data->id; failed: setup_cb_free(cb_data); return 0; } unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep, a2dp_stream_cb_t cb, void *user_data) { struct a2dp_setup_cb *cb_data; struct a2dp_setup *setup; setup = a2dp_setup_get(session); if (!setup) return 0; cb_data = setup_cb_new(setup); cb_data->resume_cb = cb; cb_data->user_data = user_data; setup->sep = sep; setup->stream = sep->stream; switch (avdtp_sep_get_state(sep->lsep)) { case AVDTP_STATE_IDLE: goto failed; break; case AVDTP_STATE_OPEN: if (avdtp_start(session, sep->stream) < 0) { error("avdtp_start failed"); goto failed; } sep->starting = TRUE; break; case AVDTP_STATE_STREAMING: if (!sep->suspending && sep->suspend_timer) { g_source_remove(sep->suspend_timer); sep->suspend_timer = 0; avdtp_unref(sep->session); sep->session = NULL; } if (sep->suspending) setup->start = TRUE; else cb_data->source_id = g_idle_add(finalize_resume, setup); break; default: error("SEP in bad state for resume"); goto failed; } return cb_data->id; failed: setup_cb_free(cb_data); return 0; } unsigned int a2dp_suspend(struct avdtp *session, struct a2dp_sep *sep, a2dp_stream_cb_t cb, void *user_data) { struct a2dp_setup_cb *cb_data; struct a2dp_setup *setup; setup = a2dp_setup_get(session); if (!setup) return 0; cb_data = setup_cb_new(setup); cb_data->suspend_cb = cb; cb_data->user_data = user_data; setup->sep = sep; setup->stream = sep->stream; switch (avdtp_sep_get_state(sep->lsep)) { case AVDTP_STATE_IDLE: error("a2dp_suspend: no stream to suspend"); goto failed; break; case AVDTP_STATE_OPEN: cb_data->source_id = g_idle_add(finalize_suspend, setup); break; case AVDTP_STATE_STREAMING: if (avdtp_suspend(session, sep->stream) < 0) { error("avdtp_suspend failed"); goto failed; } sep->suspending = TRUE; break; default: error("SEP in bad state for suspend"); goto failed; } return cb_data->id; failed: setup_cb_free(cb_data); return 0; } gboolean a2dp_cancel(struct audio_device *dev, unsigned int id) { struct a2dp_setup *setup; GSList *l; setup = find_setup_by_dev(dev); if (!setup) return FALSE; for (l = setup->cb; l != NULL; l = g_slist_next(l)) { struct a2dp_setup_cb *cb = l->data; if (cb->id != id) continue; setup_ref(setup); setup_cb_free(cb); if (!setup->cb) { DBG("aborting setup %p", setup); avdtp_abort(setup->session, setup->stream); return TRUE; } setup_unref(setup); return TRUE; } return FALSE; } gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session) { if (sep->locked) return FALSE; DBG("SEP %p locked", sep->lsep); sep->locked = TRUE; return TRUE; } gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session) { struct a2dp_server *server = sep->server; avdtp_state_t state; GSList *l; state = avdtp_sep_get_state(sep->lsep); sep->locked = FALSE; DBG("SEP %p unlocked", sep->lsep); if (sep->type == AVDTP_SEP_TYPE_SOURCE) l = server->sources; else l = server->sinks; /* Unregister sep if it was removed */ if (g_slist_find(l, sep) == NULL) { a2dp_unregister_sep(sep); return TRUE; } if (!sep->stream || state == AVDTP_STATE_IDLE) return TRUE; switch (state) { case AVDTP_STATE_OPEN: /* Set timer here */ break; case AVDTP_STATE_STREAMING: if (avdtp_suspend(session, sep->stream) == 0) sep->suspending = TRUE; break; default: break; } return TRUE; } gboolean a2dp_sep_get_lock(struct a2dp_sep *sep) { return sep->locked; } static int stream_cmp(gconstpointer data, gconstpointer user_data) { const struct a2dp_sep *sep = data; const struct avdtp_stream *stream = user_data; return (sep->stream != stream); } struct a2dp_sep *a2dp_get_sep(struct avdtp *session, struct avdtp_stream *stream) { struct a2dp_server *server; bdaddr_t src, dst; GSList *l; avdtp_get_peers(session, &src, &dst); for (l = servers; l; l = l->next) { server = l->data; if (bacmp(&src, &server->src) == 0) break; } if (!l) return NULL; l = g_slist_find_custom(server->sources, stream, stream_cmp); if (l) return l->data; l = g_slist_find_custom(server->sinks, stream, stream_cmp); if (l) return l->data; return NULL; } struct avdtp_stream *a2dp_sep_get_stream(struct a2dp_sep *sep) { return sep->stream; } bluez-4.101/audio/headset.c0000644000000000000000000020136411766125764012436 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "device.h" #include "manager.h" #include "error.h" #include "telephony.h" #include "headset.h" #include "sdp-client.h" #include "btio.h" #include "dbus-common.h" #include "../src/adapter.h" #include "../src/device.h" #define DC_TIMEOUT 3 #define RING_INTERVAL 3 #define BUF_SIZE 1024 #define HEADSET_GAIN_SPEAKER 'S' #define HEADSET_GAIN_MICROPHONE 'M' static struct { gboolean telephony_ready; /* Telephony plugin initialized */ uint32_t features; /* HFP AG features */ const struct indicator *indicators; /* Available HFP indicators */ int er_mode; /* Event reporting mode */ int er_ind; /* Event reporting for indicators */ int rh; /* Response and Hold state */ char *number; /* Incoming phone number */ int number_type; /* Incoming number type */ guint ring_timer; /* For incoming call indication */ const char *chld; /* Response to AT+CHLD=? */ } ag = { .telephony_ready = FALSE, .features = 0, .er_mode = 3, .er_ind = 0, .rh = BTRH_NOT_SUPPORTED, .number = NULL, .number_type = 0, .ring_timer = 0, }; static gboolean sco_hci = TRUE; static gboolean fast_connectable = FALSE; static GSList *active_devices = NULL; static char *str_state[] = { "HEADSET_STATE_DISCONNECTED", "HEADSET_STATE_CONNECTING", "HEADSET_STATE_CONNECTED", "HEADSET_STATE_PLAY_IN_PROGRESS", "HEADSET_STATE_PLAYING", }; struct headset_state_callback { headset_state_cb cb; void *user_data; unsigned int id; }; struct headset_nrec_callback { unsigned int id; headset_nrec_cb cb; void *user_data; }; struct connect_cb { unsigned int id; headset_stream_cb_t cb; void *cb_data; }; struct pending_connect { DBusMessage *msg; DBusPendingCall *call; GIOChannel *io; int err; headset_state_t target_state; GSList *callbacks; uint16_t svclass; }; struct headset_slc { char buf[BUF_SIZE]; int data_start; int data_length; gboolean cli_active; gboolean cme_enabled; gboolean cwa_enabled; gboolean pending_ring; gboolean inband_ring; gboolean nrec; gboolean nrec_req; int sp_gain; int mic_gain; unsigned int hf_features; }; struct headset { uint32_t hsp_handle; uint32_t hfp_handle; int rfcomm_ch; GIOChannel *rfcomm; GIOChannel *tmp_rfcomm; GIOChannel *sco; guint sco_id; gboolean auto_dc; guint dc_timer; gboolean hfp_active; gboolean search_hfp; gboolean rfcomm_initiator; headset_state_t state; struct pending_connect *pending; headset_lock_t lock; struct headset_slc *slc; GSList *nrec_cbs; }; struct event { const char *cmd; int (*callback) (struct audio_device *device, const char *buf); }; static GSList *headset_callbacks = NULL; static void error_connect_failed(DBusConnection *conn, DBusMessage *msg, int err) { DBusMessage *reply = btd_error_failed(msg, err < 0 ? strerror(-err) : "Connect failed"); g_dbus_send_message(conn, reply); } static int rfcomm_connect(struct audio_device *device, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id); static int get_records(struct audio_device *device, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id); static void print_ag_features(uint32_t features) { GString *gstr; char *str; if (features == 0) { DBG("HFP AG features: (none)"); return; } gstr = g_string_new("HFP AG features: "); if (features & AG_FEATURE_THREE_WAY_CALLING) g_string_append(gstr, "\"Three-way calling\" "); if (features & AG_FEATURE_EC_ANDOR_NR) g_string_append(gstr, "\"EC and/or NR function\" "); if (features & AG_FEATURE_VOICE_RECOGNITION) g_string_append(gstr, "\"Voice recognition function\" "); if (features & AG_FEATURE_INBAND_RINGTONE) g_string_append(gstr, "\"In-band ring tone capability\" "); if (features & AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG) g_string_append(gstr, "\"Attach a number to a voice tag\" "); if (features & AG_FEATURE_REJECT_A_CALL) g_string_append(gstr, "\"Ability to reject a call\" "); if (features & AG_FEATURE_ENHANCED_CALL_STATUS) g_string_append(gstr, "\"Enhanced call status\" "); if (features & AG_FEATURE_ENHANCED_CALL_CONTROL) g_string_append(gstr, "\"Enhanced call control\" "); if (features & AG_FEATURE_EXTENDED_ERROR_RESULT_CODES) g_string_append(gstr, "\"Extended Error Result Codes\" "); str = g_string_free(gstr, FALSE); DBG("%s", str); g_free(str); } static void print_hf_features(uint32_t features) { GString *gstr; char *str; if (features == 0) { DBG("HFP HF features: (none)"); return; } gstr = g_string_new("HFP HF features: "); if (features & HF_FEATURE_EC_ANDOR_NR) g_string_append(gstr, "\"EC and/or NR function\" "); if (features & HF_FEATURE_CALL_WAITING_AND_3WAY) g_string_append(gstr, "\"Call waiting and 3-way calling\" "); if (features & HF_FEATURE_CLI_PRESENTATION) g_string_append(gstr, "\"CLI presentation capability\" "); if (features & HF_FEATURE_VOICE_RECOGNITION) g_string_append(gstr, "\"Voice recognition activation\" "); if (features & HF_FEATURE_REMOTE_VOLUME_CONTROL) g_string_append(gstr, "\"Remote volume control\" "); if (features & HF_FEATURE_ENHANCED_CALL_STATUS) g_string_append(gstr, "\"Enhanced call status\" "); if (features & HF_FEATURE_ENHANCED_CALL_CONTROL) g_string_append(gstr, "\"Enhanced call control\" "); str = g_string_free(gstr, FALSE); DBG("%s", str); g_free(str); } static const char *state2str(headset_state_t state) { switch (state) { case HEADSET_STATE_DISCONNECTED: return "disconnected"; case HEADSET_STATE_CONNECTING: return "connecting"; case HEADSET_STATE_CONNECTED: case HEADSET_STATE_PLAY_IN_PROGRESS: return "connected"; case HEADSET_STATE_PLAYING: return "playing"; } return NULL; } static int headset_send_valist(struct headset *hs, char *format, va_list ap) { char rsp[BUF_SIZE]; ssize_t total_written, count; int fd; count = vsnprintf(rsp, sizeof(rsp), format, ap); if (count < 0) return -EINVAL; if (!hs->rfcomm) { error("headset_send: the headset is not connected"); return -EIO; } total_written = 0; fd = g_io_channel_unix_get_fd(hs->rfcomm); while (total_written < count) { ssize_t written; written = write(fd, rsp + total_written, count - total_written); if (written < 0) return -errno; total_written += written; } return 0; } static int __attribute__((format(printf, 2, 3))) headset_send(struct headset *hs, char *format, ...) { va_list ap; int ret; va_start(ap, format); ret = headset_send_valist(hs, format, ap); va_end(ap); return ret; } static int supported_features(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; int err; if (strlen(buf) < 9) return -EINVAL; slc->hf_features = strtoul(&buf[8], NULL, 10); print_hf_features(slc->hf_features); err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features); if (err < 0) return err; return headset_send(hs, "\r\nOK\r\n"); } static char *indicator_ranges(const struct indicator *indicators) { int i; GString *gstr; gstr = g_string_new("\r\n+CIND: "); for (i = 0; indicators[i].desc != NULL; i++) { if (i == 0) g_string_append_printf(gstr, "(\"%s\",(%s))", indicators[i].desc, indicators[i].range); else g_string_append_printf(gstr, ",(\"%s\",(%s))", indicators[i].desc, indicators[i].range); } g_string_append(gstr, "\r\n"); return g_string_free(gstr, FALSE); } static char *indicator_values(const struct indicator *indicators) { int i; GString *gstr; gstr = g_string_new("\r\n+CIND: "); for (i = 0; indicators[i].desc != NULL; i++) { if (i == 0) g_string_append_printf(gstr, "%d", indicators[i].val); else g_string_append_printf(gstr, ",%d", indicators[i].val); } g_string_append(gstr, "\r\n"); return g_string_free(gstr, FALSE); } static int report_indicators(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; int err; char *str; if (strlen(buf) < 8) return -EINVAL; if (ag.indicators == NULL) { error("HFP AG indicators not initialized"); return headset_send(hs, "\r\nERROR\r\n"); } if (buf[7] == '=') str = indicator_ranges(ag.indicators); else str = indicator_values(ag.indicators); err = headset_send(hs, "%s", str); g_free(str); if (err < 0) return err; return headset_send(hs, "\r\nOK\r\n"); } static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev) { struct headset *hs = dev->headset; if (hs->pending->err < 0) cb->cb(NULL, cb->cb_data); else cb->cb(dev, cb->cb_data); } static void pending_connect_finalize(struct audio_device *dev) { struct headset *hs = dev->headset; struct pending_connect *p = hs->pending; if (p == NULL) return; if (p->svclass) bt_cancel_discovery(&dev->src, &dev->dst); g_slist_foreach(p->callbacks, (GFunc) pending_connect_complete, dev); g_slist_free_full(p->callbacks, g_free); if (p->io) { g_io_channel_shutdown(p->io, TRUE, NULL); g_io_channel_unref(p->io); } if (p->msg) dbus_message_unref(p->msg); if (p->call) { dbus_pending_call_cancel(p->call); dbus_pending_call_unref(p->call); } g_free(p); hs->pending = NULL; } static void pending_connect_init(struct headset *hs, headset_state_t target_state) { if (hs->pending) { if (hs->pending->target_state < target_state) hs->pending->target_state = target_state; return; } hs->pending = g_new0(struct pending_connect, 1); hs->pending->target_state = target_state; } static unsigned int connect_cb_new(struct headset *hs, headset_state_t target_state, headset_stream_cb_t func, void *user_data) { struct connect_cb *cb; static unsigned int free_cb_id = 1; pending_connect_init(hs, target_state); if (!func) return 0; cb = g_new(struct connect_cb, 1); cb->cb = func; cb->cb_data = user_data; cb->id = free_cb_id++; hs->pending->callbacks = g_slist_append(hs->pending->callbacks, cb); return cb->id; } static void __attribute__((format(printf, 3, 4))) send_foreach_headset(GSList *devices, int (*cmp) (struct headset *hs), char *format, ...) { GSList *l; va_list ap; for (l = devices; l != NULL; l = l->next) { struct audio_device *device = l->data; struct headset *hs = device->headset; int ret; assert(hs != NULL); if (cmp && cmp(hs) != 0) continue; va_start(ap, format); ret = headset_send_valist(hs, format, ap); if (ret < 0) error("Failed to send to headset: %s (%d)", strerror(-ret), -ret); va_end(ap); } } static int cli_cmp(struct headset *hs) { struct headset_slc *slc = hs->slc; if (!hs->hfp_active) return -1; if (slc->cli_active) return 0; else return -1; } static gboolean ring_timer_cb(gpointer data) { send_foreach_headset(active_devices, NULL, "\r\nRING\r\n"); if (ag.number) send_foreach_headset(active_devices, cli_cmp, "\r\n+CLIP: \"%s\",%d\r\n", ag.number, ag.number_type); return TRUE; } static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { int sk; struct audio_device *dev = user_data; struct headset *hs = dev->headset; struct headset_slc *slc = hs->slc; struct pending_connect *p = hs->pending; if (err) { error("%s", err->message); if (p != NULL) { p->err = -errno; if (p->msg) error_connect_failed(dev->conn, p->msg, p->err); pending_connect_finalize(dev); } if (hs->rfcomm) headset_set_state(dev, HEADSET_STATE_CONNECTED); else headset_set_state(dev, HEADSET_STATE_DISCONNECTED); return; } DBG("SCO socket opened for headset %s", dev->path); sk = g_io_channel_unix_get_fd(chan); DBG("SCO fd=%d", sk); if (p) { p->io = NULL; if (p->msg) { DBusMessage *reply; reply = dbus_message_new_method_return(p->msg); g_dbus_send_message(dev->conn, reply); } pending_connect_finalize(dev); } fcntl(sk, F_SETFL, 0); headset_set_state(dev, HEADSET_STATE_PLAYING); if (slc->pending_ring) { ring_timer_cb(NULL); ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb, NULL); slc->pending_ring = FALSE; } } static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id) { struct headset *hs = dev->headset; GError *err = NULL; GIOChannel *io; if (hs->state != HEADSET_STATE_CONNECTED) return -EINVAL; io = bt_io_connect(BT_IO_SCO, sco_connect_cb, dev, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &dev->src, BT_IO_OPT_DEST_BDADDR, &dev->dst, BT_IO_OPT_INVALID); if (!io) { error("%s", err->message); g_error_free(err); return -EIO; } hs->sco = io; headset_set_state(dev, HEADSET_STATE_PLAY_IN_PROGRESS); pending_connect_init(hs, HEADSET_STATE_PLAYING); if (cb) { unsigned int id = connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data); if (cb_id) *cb_id = id; } return 0; } static int hfp_cmp(struct headset *hs) { if (hs->hfp_active) return 0; else return -1; } static void hfp_slc_complete(struct audio_device *dev) { struct headset *hs = dev->headset; struct pending_connect *p = hs->pending; DBG("HFP Service Level Connection established"); headset_set_state(dev, HEADSET_STATE_CONNECTED); if (p == NULL) return; if (p->target_state == HEADSET_STATE_CONNECTED) { if (p->msg) { DBusMessage *reply = dbus_message_new_method_return(p->msg); g_dbus_send_message(dev->conn, reply); } pending_connect_finalize(dev); return; } p->err = sco_connect(dev, NULL, NULL, NULL); if (p->err < 0) { if (p->msg) error_connect_failed(dev->conn, p->msg, p->err); pending_connect_finalize(dev); } } static int telephony_generic_rsp(struct audio_device *device, cme_error_t err) { struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; if ((err != CME_ERROR_NONE) && slc->cme_enabled) return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err); switch (err) { case CME_ERROR_NONE: return headset_send(hs, "\r\nOK\r\n"); case CME_ERROR_NO_NETWORK_SERVICE: return headset_send(hs, "\r\nNO CARRIER\r\n"); default: return headset_send(hs, "\r\nERROR\r\n"); } } int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err) { struct audio_device *device = telephony_device; struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; int ret; if (err != CME_ERROR_NONE) return telephony_generic_rsp(telephony_device, err); ret = headset_send(hs, "\r\nOK\r\n"); if (ret < 0) return ret; if (hs->state != HEADSET_STATE_CONNECTING) return 0; if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY && ag.features & AG_FEATURE_THREE_WAY_CALLING) return 0; hfp_slc_complete(device); return 0; } static int event_reporting(struct audio_device *dev, const char *buf) { char **tokens; /* , , , , */ if (strlen(buf) < 13) return -EINVAL; tokens = g_strsplit(&buf[8], ",", 5); if (g_strv_length(tokens) < 4) { g_strfreev(tokens); return -EINVAL; } ag.er_mode = atoi(tokens[0]); ag.er_ind = atoi(tokens[3]); g_strfreev(tokens); tokens = NULL; DBG("Event reporting (CMER): mode=%d, ind=%d", ag.er_mode, ag.er_ind); switch (ag.er_ind) { case 0: case 1: telephony_event_reporting_req(dev, ag.er_ind); break; default: return -EINVAL; } return 0; } static int call_hold(struct audio_device *dev, const char *buf) { struct headset *hs = dev->headset; int err; if (strlen(buf) < 9) return -EINVAL; if (buf[8] != '?') { telephony_call_hold_req(dev, &buf[8]); return 0; } err = headset_send(hs, "\r\n+CHLD: (%s)\r\n", ag.chld); if (err < 0) return err; err = headset_send(hs, "\r\nOK\r\n"); if (err < 0) return err; if (hs->state != HEADSET_STATE_CONNECTING) return 0; hfp_slc_complete(dev); return 0; } int telephony_key_press_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } static int key_press(struct audio_device *device, const char *buf) { if (strlen(buf) < 9) return -EINVAL; g_dbus_emit_signal(device->conn, device->path, AUDIO_HEADSET_INTERFACE, "AnswerRequested", DBUS_TYPE_INVALID); if (ag.ring_timer) { g_source_remove(ag.ring_timer); ag.ring_timer = 0; } telephony_key_press_req(device, &buf[8]); return 0; } int telephony_answer_call_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } static int answer_call(struct audio_device *device, const char *buf) { if (ag.ring_timer) { g_source_remove(ag.ring_timer); ag.ring_timer = 0; } if (ag.number) { g_free(ag.number); ag.number = NULL; } telephony_answer_call_req(device); return 0; } int telephony_terminate_call_rsp(void *telephony_device, cme_error_t err) { struct audio_device *device = telephony_device; struct headset *hs = device->headset; if (err != CME_ERROR_NONE) return telephony_generic_rsp(telephony_device, err); g_dbus_emit_signal(device->conn, device->path, AUDIO_HEADSET_INTERFACE, "CallTerminated", DBUS_TYPE_INVALID); return headset_send(hs, "\r\nOK\r\n"); } static int terminate_call(struct audio_device *device, const char *buf) { if (ag.number) { g_free(ag.number); ag.number = NULL; } if (ag.ring_timer) { g_source_remove(ag.ring_timer); ag.ring_timer = 0; } telephony_terminate_call_req(device); return 0; } static int cli_notification(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; if (strlen(buf) < 9) return -EINVAL; slc->cli_active = buf[8] == '1' ? TRUE : FALSE; return headset_send(hs, "\r\nOK\r\n"); } int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } static int response_and_hold(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; if (strlen(buf) < 8) return -EINVAL; if (ag.rh == BTRH_NOT_SUPPORTED) return telephony_generic_rsp(device, CME_ERROR_NOT_SUPPORTED); if (buf[7] == '=') { telephony_response_and_hold_req(device, atoi(&buf[8]) < 0); return 0; } if (ag.rh >= 0) headset_send(hs, "\r\n+BTRH: %d\r\n", ag.rh); return headset_send(hs, "\r\nOK\r\n"); } int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } static int last_dialed_number(struct audio_device *device, const char *buf) { telephony_last_dialed_number_req(device); return 0; } int telephony_dial_number_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } static int dial_number(struct audio_device *device, const char *buf) { char number[BUF_SIZE]; size_t buf_len; buf_len = strlen(buf); if (buf[buf_len - 1] != ';') { DBG("Rejecting non-voice call dial request"); return -EINVAL; } memset(number, 0, sizeof(number)); strncpy(number, &buf[3], buf_len - 4); telephony_dial_number_req(device, number); return 0; } static int headset_set_gain(struct audio_device *device, uint16_t gain, char type) { struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; const char *name, *property; if (gain > 15) { error("Invalid gain value: %u", gain); return -EINVAL; } switch (type) { case HEADSET_GAIN_SPEAKER: if (slc->sp_gain == gain) { DBG("Ignoring no-change in speaker gain"); return -EALREADY; } name = "SpeakerGainChanged"; property = "SpeakerGain"; slc->sp_gain = gain; break; case HEADSET_GAIN_MICROPHONE: if (slc->mic_gain == gain) { DBG("Ignoring no-change in microphone gain"); return -EALREADY; } name = "MicrophoneGainChanged"; property = "MicrophoneGain"; slc->mic_gain = gain; break; default: error("Unknown gain setting"); return -EINVAL; } g_dbus_emit_signal(device->conn, device->path, AUDIO_HEADSET_INTERFACE, name, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); emit_property_changed(device->conn, device->path, AUDIO_HEADSET_INTERFACE, property, DBUS_TYPE_UINT16, &gain); return 0; } static int signal_gain_setting(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; dbus_uint16_t gain; int err; if (strlen(buf) < 8) { error("Too short string for Gain setting"); return -EINVAL; } gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10); err = headset_set_gain(device, gain, buf[5]); if (err < 0 && err != -EALREADY) return err; return headset_send(hs, "\r\nOK\r\n"); } int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } static int dtmf_tone(struct audio_device *device, const char *buf) { char tone; if (strlen(buf) < 8) { error("Too short string for DTMF tone"); return -EINVAL; } tone = buf[7]; if (tone >= '#' && tone <= 'D') telephony_transmit_dtmf_req(device, tone); else return -EINVAL; return 0; } int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } static int subscriber_number(struct audio_device *device, const char *buf) { telephony_subscriber_number_req(device); return 0; } int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } static int list_current_calls(struct audio_device *device, const char *buf) { telephony_list_current_calls_req(device); return 0; } static int extended_errors(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; if (strlen(buf) < 9) return -EINVAL; if (buf[8] == '1') { slc->cme_enabled = TRUE; DBG("CME errors enabled for headset %p", hs); } else { slc->cme_enabled = FALSE; DBG("CME errors disabled for headset %p", hs); } return headset_send(hs, "\r\nOK\r\n"); } static int call_waiting_notify(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; if (strlen(buf) < 9) return -EINVAL; if (buf[8] == '1') { slc->cwa_enabled = TRUE; DBG("Call waiting notification enabled for headset %p", hs); } else { slc->cwa_enabled = FALSE; DBG("Call waiting notification disabled for headset %p", hs); } return headset_send(hs, "\r\nOK\r\n"); } int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } int telephony_call_hold_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err) { struct audio_device *device = telephony_device; struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; if (err == CME_ERROR_NONE) { GSList *l; for (l = hs->nrec_cbs; l; l = l->next) { struct headset_nrec_callback *nrec_cb = l->data; nrec_cb->cb(device, slc->nrec_req, nrec_cb->user_data); } slc->nrec = hs->slc->nrec_req; } return telephony_generic_rsp(telephony_device, err); } int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err) { return telephony_generic_rsp(telephony_device, err); } int telephony_operator_selection_ind(int mode, const char *oper) { if (!active_devices) return -ENODEV; send_foreach_headset(active_devices, hfp_cmp, "\r\n+COPS: %d,0,\"%s\"\r\n", mode, oper); return 0; } static int operator_selection(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; if (strlen(buf) < 8) return -EINVAL; switch (buf[7]) { case '?': telephony_operator_selection_req(device); break; case '=': return headset_send(hs, "\r\nOK\r\n"); default: return -EINVAL; } return 0; } static int nr_and_ec(struct audio_device *device, const char *buf) { struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; if (strlen(buf) < 9) return -EINVAL; if (buf[8] == '0') slc->nrec_req = FALSE; else slc->nrec_req = TRUE; telephony_nr_and_ec_req(device, slc->nrec_req); return 0; } static int voice_dial(struct audio_device *device, const char *buf) { gboolean enable; if (strlen(buf) < 9) return -EINVAL; if (buf[8] == '0') enable = FALSE; else enable = TRUE; telephony_voice_dial_req(device, enable); return 0; } static int apple_command(struct audio_device *device, const char *buf) { DBG("Got Apple command: %s", buf); return telephony_generic_rsp(device, CME_ERROR_NONE); } static struct event event_callbacks[] = { { "ATA", answer_call }, { "ATD", dial_number }, { "AT+VG", signal_gain_setting }, { "AT+BRSF", supported_features }, { "AT+CIND", report_indicators }, { "AT+CMER", event_reporting }, { "AT+CHLD", call_hold }, { "AT+CHUP", terminate_call }, { "AT+CKPD", key_press }, { "AT+CLIP", cli_notification }, { "AT+BTRH", response_and_hold }, { "AT+BLDN", last_dialed_number }, { "AT+VTS", dtmf_tone }, { "AT+CNUM", subscriber_number }, { "AT+CLCC", list_current_calls }, { "AT+CMEE", extended_errors }, { "AT+CCWA", call_waiting_notify }, { "AT+COPS", operator_selection }, { "AT+NREC", nr_and_ec }, { "AT+BVRA", voice_dial }, { "AT+XAPL", apple_command }, { "AT+IPHONEACCEV", apple_command }, { 0 } }; static int handle_event(struct audio_device *device, const char *buf) { struct event *ev; DBG("Received %s", buf); for (ev = event_callbacks; ev->cmd; ev++) { if (!strncmp(buf, ev->cmd, strlen(ev->cmd))) return ev->callback(device, buf); } return -EINVAL; } static void close_sco(struct audio_device *device) { struct headset *hs = device->headset; if (hs->sco) { int sock = g_io_channel_unix_get_fd(hs->sco); shutdown(sock, SHUT_RDWR); g_io_channel_shutdown(hs->sco, TRUE, NULL); g_io_channel_unref(hs->sco); hs->sco = NULL; } if (hs->sco_id) { g_source_remove(hs->sco_id); hs->sco_id = 0; } } static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, struct audio_device *device) { struct headset *hs; struct headset_slc *slc; unsigned char buf[BUF_SIZE]; ssize_t bytes_read; size_t free_space; int fd; if (cond & G_IO_NVAL) return FALSE; hs = device->headset; slc = hs->slc; if (cond & (G_IO_ERR | G_IO_HUP)) { DBG("ERR or HUP on RFCOMM socket"); goto failed; } fd = g_io_channel_unix_get_fd(chan); bytes_read = read(fd, buf, sizeof(buf) - 1); if (bytes_read < 0) return TRUE; free_space = sizeof(slc->buf) - slc->data_start - slc->data_length - 1; if (free_space < (size_t) bytes_read) { /* Very likely that the HS is sending us garbage so * just ignore the data and disconnect */ error("Too much data to fit incoming buffer"); goto failed; } memcpy(&slc->buf[slc->data_start], buf, bytes_read); slc->data_length += bytes_read; /* Make sure the data is null terminated so we can use string * functions */ slc->buf[slc->data_start + slc->data_length] = '\0'; while (slc->data_length > 0) { char *cr; int err; off_t cmd_len; cr = strchr(&slc->buf[slc->data_start], '\r'); if (!cr) break; cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start]; *cr = '\0'; if (cmd_len > 1) err = handle_event(device, &slc->buf[slc->data_start]); else /* Silently skip empty commands */ err = 0; if (err == -EINVAL) { error("Badly formated or unrecognized command: %s", &slc->buf[slc->data_start]); err = telephony_generic_rsp(device, CME_ERROR_NOT_SUPPORTED); if (err < 0) goto failed; } else if (err < 0) error("Error handling command %s: %s (%d)", &slc->buf[slc->data_start], strerror(-err), -err); slc->data_start += cmd_len; slc->data_length -= cmd_len; if (!slc->data_length) slc->data_start = 0; } return TRUE; failed: headset_set_state(device, HEADSET_STATE_DISCONNECTED); return FALSE; } static gboolean sco_cb(GIOChannel *chan, GIOCondition cond, struct audio_device *device) { if (cond & G_IO_NVAL) return FALSE; error("Audio connection got disconnected"); pending_connect_finalize(device); headset_set_state(device, HEADSET_STATE_CONNECTED); return FALSE; } void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct audio_device *dev = user_data; struct headset *hs = dev->headset; struct pending_connect *p = hs->pending; char hs_address[18]; if (err) { error("%s", err->message); goto failed; } /* For HFP telephony isn't ready just disconnect */ if (hs->hfp_active && !ag.telephony_ready) { error("Unable to accept HFP connection since the telephony " "subsystem isn't initialized"); goto failed; } hs->rfcomm = hs->tmp_rfcomm; hs->tmp_rfcomm = NULL; ba2str(&dev->dst, hs_address); if (p) p->io = NULL; else hs->auto_dc = FALSE; g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL, (GIOFunc) rfcomm_io_cb, dev); DBG("%s: Connected to %s", dev->path, hs_address); hs->slc = g_new0(struct headset_slc, 1); hs->slc->sp_gain = 15; hs->slc->mic_gain = 15; hs->slc->nrec = TRUE; /* In HFP mode wait for Service Level Connection */ if (hs->hfp_active) return; headset_set_state(dev, HEADSET_STATE_CONNECTED); if (p && p->target_state == HEADSET_STATE_PLAYING) { p->err = sco_connect(dev, NULL, NULL, NULL); if (p->err < 0) goto failed; return; } if (p && p->msg) { DBusMessage *reply = dbus_message_new_method_return(p->msg); g_dbus_send_message(dev->conn, reply); } pending_connect_finalize(dev); return; failed: if (p && p->msg) error_connect_failed(dev->conn, p->msg, p->err); pending_connect_finalize(dev); if (hs->rfcomm) headset_set_state(dev, HEADSET_STATE_CONNECTED); else headset_set_state(dev, HEADSET_STATE_DISCONNECTED); } static int headset_set_channel(struct headset *headset, const sdp_record_t *record, uint16_t svc) { int ch; sdp_list_t *protos; if (sdp_get_access_protos(record, &protos) < 0) { error("Unable to get access protos from headset record"); return -1; } ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); if (ch <= 0) { error("Unable to get RFCOMM channel from Headset record"); return -1; } headset->rfcomm_ch = ch; if (svc == HANDSFREE_SVCLASS_ID) { headset->hfp_handle = record->handle; headset->hsp_handle = 0; DBG("Discovered Handsfree service on channel %d", ch); } else { headset->hsp_handle = record->handle; headset->hfp_handle = 0; DBG("Discovered Headset service on channel %d", ch); } return 0; } static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct audio_device *dev = user_data; struct headset *hs = dev->headset; struct pending_connect *p = hs->pending; sdp_record_t *record = NULL; sdp_list_t *r; uuid_t uuid; assert(hs->pending != NULL); if (err < 0) { error("Unable to get service record: %s (%d)", strerror(-err), -err); p->err = -err; if (p->msg) error_connect_failed(dev->conn, p->msg, p->err); goto failed; } if (!recs || !recs->data) { error("No records found"); goto failed_not_supported; } sdp_uuid16_create(&uuid, p->svclass); for (r = recs; r != NULL; r = r->next) { sdp_list_t *classes; uuid_t class; record = r->data; if (sdp_get_service_classes(record, &classes) < 0) { error("Unable to get service classes from record"); continue; } memcpy(&class, classes->data, sizeof(uuid)); sdp_list_free(classes, free); if (sdp_uuid_cmp(&class, &uuid) == 0) break; } if (r == NULL) { error("No record found with UUID 0x%04x", p->svclass); goto failed_not_supported; } if (headset_set_channel(hs, record, p->svclass) < 0) { error("Unable to extract RFCOMM channel from service record"); goto failed_not_supported; } /* Set svclass to 0 so we can easily check that SDP is no-longer * going on (to know if bt_cancel_discovery needs to be called) */ p->svclass = 0; err = rfcomm_connect(dev, NULL, NULL, NULL); if (err < 0) { error("Unable to connect: %s (%d)", strerror(-err), -err); p->err = -err; if (p->msg != NULL) error_connect_failed(dev->conn, p->msg, p->err); goto failed; } return; failed_not_supported: if (p->svclass == HANDSFREE_SVCLASS_ID && get_records(dev, NULL, NULL, NULL) == 0) return; if (p->msg) { DBusMessage *reply = btd_error_not_supported(p->msg); g_dbus_send_message(dev->conn, reply); } failed: p->svclass = 0; pending_connect_finalize(dev); headset_set_state(dev, HEADSET_STATE_DISCONNECTED); } static int get_records(struct audio_device *device, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id) { struct headset *hs = device->headset; uint16_t svclass; uuid_t uuid; int err; if (hs->pending && hs->pending->svclass == HANDSFREE_SVCLASS_ID) svclass = HEADSET_SVCLASS_ID; else svclass = hs->search_hfp ? HANDSFREE_SVCLASS_ID : HEADSET_SVCLASS_ID; sdp_uuid16_create(&uuid, svclass); err = bt_search_service(&device->src, &device->dst, &uuid, get_record_cb, device, NULL); if (err < 0) return err; if (hs->pending) { hs->pending->svclass = svclass; return 0; } headset_set_state(device, HEADSET_STATE_CONNECTING); pending_connect_init(hs, HEADSET_STATE_CONNECTED); hs->pending->svclass = svclass; if (cb) { unsigned int id; id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data); if (cb_id) *cb_id = id; } return 0; } static int rfcomm_connect(struct audio_device *dev, headset_stream_cb_t cb, void *user_data, unsigned int *cb_id) { struct headset *hs = dev->headset; char address[18]; GError *err = NULL; if (!manager_allow_headset_connection(dev)) return -ECONNREFUSED; if (hs->rfcomm_ch < 0) return get_records(dev, cb, user_data, cb_id); ba2str(&dev->dst, address); DBG("%s: Connecting to %s channel %d", dev->path, address, hs->rfcomm_ch); hs->tmp_rfcomm = bt_io_connect(BT_IO_RFCOMM, headset_connect_cb, dev, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &dev->src, BT_IO_OPT_DEST_BDADDR, &dev->dst, BT_IO_OPT_CHANNEL, hs->rfcomm_ch, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID); hs->rfcomm_ch = -1; if (!hs->tmp_rfcomm) { error("%s", err->message); g_error_free(err); return -EIO; } hs->hfp_active = hs->hfp_handle != 0 ? TRUE : FALSE; hs->rfcomm_initiator = FALSE; headset_set_state(dev, HEADSET_STATE_CONNECTING); pending_connect_init(hs, HEADSET_STATE_CONNECTED); if (cb) { unsigned int id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data); if (cb_id) *cb_id = id; } return 0; } static DBusMessage *hs_stop(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; if (hs->state < HEADSET_STATE_PLAY_IN_PROGRESS) return btd_error_not_connected(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; headset_set_state(device, HEADSET_STATE_CONNECTED); return reply; } static DBusMessage *hs_is_playing(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; DBusMessage *reply; dbus_bool_t playing; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; playing = (hs->state == HEADSET_STATE_PLAYING); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing, DBUS_TYPE_INVALID); return reply; } static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; char hs_address[18]; if (hs->state == HEADSET_STATE_DISCONNECTED) return btd_error_not_connected(msg); headset_shutdown(device); ba2str(&device->dst, hs_address); info("Disconnected from %s, %s", hs_address, device->path); return dbus_message_new_method_return(msg); } static DBusMessage *hs_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; DBusMessage *reply; dbus_bool_t connected; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; connected = (device->headset->state >= HEADSET_STATE_CONNECTED); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, DBUS_TYPE_INVALID); return reply; } static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; int err; if (hs->state == HEADSET_STATE_CONNECTING) return btd_error_in_progress(msg); else if (hs->state > HEADSET_STATE_CONNECTING) return btd_error_already_connected(msg); if (hs->hfp_handle && !ag.telephony_ready) return btd_error_not_ready(msg); device->auto_connect = FALSE; err = rfcomm_connect(device, NULL, NULL, NULL); if (err < 0) return btd_error_failed(msg, strerror(-err)); hs->auto_dc = FALSE; hs->pending->msg = dbus_message_ref(msg); return NULL; } static DBusMessage *hs_ring(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; int err; if (hs->state < HEADSET_STATE_CONNECTED) return btd_error_not_connected(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; if (ag.ring_timer) { DBG("IndicateCall received when already indicating"); return reply; } err = headset_send(hs, "\r\nRING\r\n"); if (err < 0) { dbus_message_unref(reply); return btd_error_failed(msg, strerror(-err)); } ring_timer_cb(NULL); ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb, NULL); return reply; } static DBusMessage *hs_cancel_call(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; DBusMessage *reply = NULL; if (hs->state < HEADSET_STATE_CONNECTED) return btd_error_not_connected(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; if (ag.ring_timer) { g_source_remove(ag.ring_timer); ag.ring_timer = 0; } else DBG("Got CancelCall method call but no call is active"); return reply; } static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; int err; if (sco_hci) { error("Refusing Headset.Play() because SCO HCI routing " "is enabled"); return btd_error_not_available(msg); } switch (hs->state) { case HEADSET_STATE_DISCONNECTED: case HEADSET_STATE_CONNECTING: return btd_error_not_connected(msg); case HEADSET_STATE_PLAY_IN_PROGRESS: if (hs->pending && hs->pending->msg == NULL) { hs->pending->msg = dbus_message_ref(msg); return NULL; } return btd_error_busy(msg); case HEADSET_STATE_PLAYING: return btd_error_already_connected(msg); case HEADSET_STATE_CONNECTED: default: break; } err = sco_connect(device, NULL, NULL, NULL); if (err < 0) return btd_error_failed(msg, strerror(-err)); hs->pending->msg = dbus_message_ref(msg); return NULL; } static DBusMessage *hs_get_speaker_gain(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; DBusMessage *reply; dbus_uint16_t gain; if (hs->state < HEADSET_STATE_CONNECTED) return btd_error_not_available(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; gain = (dbus_uint16_t) slc->sp_gain; dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); return reply; } static DBusMessage *hs_get_mic_gain(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct headset *hs = device->headset; struct headset_slc *slc = hs->slc; DBusMessage *reply; dbus_uint16_t gain; if (hs->state < HEADSET_STATE_CONNECTED || slc == NULL) return btd_error_not_available(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; gain = (dbus_uint16_t) slc->mic_gain; dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID); return reply; } static DBusMessage *hs_set_gain(DBusConnection *conn, DBusMessage *msg, void *data, uint16_t gain, char type) { struct audio_device *device = data; struct headset *hs = device->headset; DBusMessage *reply; int err; if (hs->state < HEADSET_STATE_CONNECTED) return btd_error_not_connected(msg); err = headset_set_gain(device, gain, type); if (err < 0) return btd_error_invalid_args(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; if (hs->state == HEADSET_STATE_PLAYING) { err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain); if (err < 0) { dbus_message_unref(reply); return btd_error_failed(msg, strerror(-err)); } } return reply; } static DBusMessage *hs_set_speaker_gain(DBusConnection *conn, DBusMessage *msg, void *data) { uint16_t gain; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID)) return NULL; return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER); } static DBusMessage *hs_set_mic_gain(DBusConnection *conn, DBusMessage *msg, void *data) { uint16_t gain; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain, DBUS_TYPE_INVALID)) return NULL; return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE); } static DBusMessage *hs_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; gboolean value; const char *state; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Playing */ value = (device->headset->state == HEADSET_STATE_PLAYING); dict_append_entry(&dict, "Playing", DBUS_TYPE_BOOLEAN, &value); /* State */ state = state2str(device->headset->state); if (state) dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state); /* Connected */ value = (device->headset->state >= HEADSET_STATE_CONNECTED); dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value); if (!value) goto done; /* SpeakerGain */ dict_append_entry(&dict, "SpeakerGain", DBUS_TYPE_UINT16, &device->headset->slc->sp_gain); /* MicrophoneGain */ dict_append_entry(&dict, "MicrophoneGain", DBUS_TYPE_UINT16, &device->headset->slc->mic_gain); done: dbus_message_iter_close_container(&iter, &dict); return reply; } static DBusMessage *hs_set_property(DBusConnection *conn, DBusMessage *msg, void *data) { const char *property; DBusMessageIter iter; DBusMessageIter sub; uint16_t gain; if (!dbus_message_iter_init(msg, &iter)) return btd_error_invalid_args(msg); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return btd_error_invalid_args(msg); dbus_message_iter_recurse(&iter, &sub); if (g_str_equal("SpeakerGain", property)) { if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &gain); return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER); } else if (g_str_equal("MicrophoneGain", property)) { if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &gain); return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE); } return btd_error_invalid_args(msg); } static const GDBusMethodTable headset_methods[] = { { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, hs_connect) }, { GDBUS_METHOD("Disconnect", NULL, NULL, hs_disconnect) }, { GDBUS_METHOD("IsConnected", NULL, GDBUS_ARGS({ "connected", "b" }), hs_is_connected) }, { GDBUS_METHOD("IndicateCall", NULL, NULL, hs_ring) }, { GDBUS_METHOD("CancelCall", NULL, NULL, hs_cancel_call) }, { GDBUS_DEPRECATED_ASYNC_METHOD("Play", NULL, NULL, hs_play) }, { GDBUS_METHOD("Stop", NULL, NULL, hs_stop) }, { GDBUS_DEPRECATED_METHOD("IsPlaying", NULL, GDBUS_ARGS({ "playing", "b" }), hs_is_playing) }, { GDBUS_DEPRECATED_METHOD("GetSpeakerGain", NULL, GDBUS_ARGS({ "gain", "q" }), hs_get_speaker_gain) }, { GDBUS_DEPRECATED_METHOD("GetMicrophoneGain", NULL, GDBUS_ARGS({ "gain", "q" }), hs_get_mic_gain) }, { GDBUS_DEPRECATED_METHOD("SetSpeakerGain", GDBUS_ARGS({ "gain", "q" }), NULL, hs_set_speaker_gain) }, { GDBUS_DEPRECATED_METHOD("SetMicrophoneGain", GDBUS_ARGS({ "gain", "q" }), NULL, hs_set_mic_gain) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), hs_get_properties) }, { GDBUS_METHOD("SetProperty", GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL, hs_set_property) }, { } }; static const GDBusSignalTable headset_signals[] = { { GDBUS_DEPRECATED_SIGNAL("Connected", NULL) }, { GDBUS_DEPRECATED_SIGNAL("Disconnected", NULL) }, { GDBUS_DEPRECATED_SIGNAL("AnswerRequested", NULL) }, { GDBUS_DEPRECATED_SIGNAL("Stopped", NULL) }, { GDBUS_DEPRECATED_SIGNAL("Playing", NULL) }, { GDBUS_DEPRECATED_SIGNAL("SpeakerGainChanged", GDBUS_ARGS({ "gain", "q" })) }, { GDBUS_DEPRECATED_SIGNAL("MicrophoneGainChanged", GDBUS_ARGS({ "gain", "q" })) }, { GDBUS_SIGNAL("CallTerminated", NULL) }, { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; void headset_update(struct audio_device *dev, uint16_t svc, const char *uuidstr) { struct headset *headset = dev->headset; const sdp_record_t *record; record = btd_device_get_record(dev->btd_dev, uuidstr); if (!record) return; switch (svc) { case HANDSFREE_SVCLASS_ID: if (headset->hfp_handle && (headset->hfp_handle != record->handle)) { error("More than one HFP record found on device"); return; } headset->hfp_handle = record->handle; break; case HEADSET_SVCLASS_ID: if (headset->hsp_handle && (headset->hsp_handle != record->handle)) { error("More than one HSP record found on device"); return; } headset->hsp_handle = record->handle; /* Ignore this record if we already have access to HFP */ if (headset->hfp_handle) return; break; default: DBG("Invalid record passed to headset_update"); return; } } static int headset_close_rfcomm(struct audio_device *dev) { struct headset *hs = dev->headset; GIOChannel *rfcomm = hs->tmp_rfcomm ? hs->tmp_rfcomm : hs->rfcomm; if (rfcomm) { g_io_channel_shutdown(rfcomm, TRUE, NULL); g_io_channel_unref(rfcomm); hs->tmp_rfcomm = NULL; hs->rfcomm = NULL; } g_free(hs->slc); hs->slc = NULL; return 0; } static void headset_free(struct audio_device *dev) { struct headset *hs = dev->headset; if (hs->dc_timer) { g_source_remove(hs->dc_timer); hs->dc_timer = 0; } close_sco(dev); headset_close_rfcomm(dev); g_slist_free_full(hs->nrec_cbs, g_free); g_free(hs); dev->headset = NULL; } static void path_unregister(void *data) { struct audio_device *dev = data; struct headset *hs = dev->headset; if (hs->state > HEADSET_STATE_DISCONNECTED) { DBG("Headset unregistered while device was connected!"); headset_shutdown(dev); } DBG("Unregistered interface %s on path %s", AUDIO_HEADSET_INTERFACE, dev->path); headset_free(dev); } void headset_unregister(struct audio_device *dev) { g_dbus_unregister_interface(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE); } struct headset *headset_init(struct audio_device *dev, uint16_t svc, const char *uuidstr) { struct headset *hs; const sdp_record_t *record; hs = g_new0(struct headset, 1); hs->rfcomm_ch = -1; hs->search_hfp = server_is_enabled(&dev->src, HANDSFREE_SVCLASS_ID); record = btd_device_get_record(dev->btd_dev, uuidstr); if (!record) goto register_iface; switch (svc) { case HANDSFREE_SVCLASS_ID: hs->hfp_handle = record->handle; break; case HEADSET_SVCLASS_ID: hs->hsp_handle = record->handle; break; default: DBG("Invalid record passed to headset_init"); g_free(hs); return NULL; } register_iface: if (!g_dbus_register_interface(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, headset_methods, headset_signals, NULL, dev, path_unregister)) { g_free(hs); return NULL; } DBG("Registered interface %s on path %s", AUDIO_HEADSET_INTERFACE, dev->path); return hs; } uint32_t headset_config_init(GKeyFile *config) { GError *err = NULL; char *str; /* Use the default values if there is no config file */ if (config == NULL) return ag.features; str = g_key_file_get_string(config, "General", "SCORouting", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else { if (strcmp(str, "PCM") == 0) sco_hci = FALSE; else if (strcmp(str, "HCI") == 0) sco_hci = TRUE; else error("Invalid Headset Routing value: %s", str); g_free(str); } /* Init fast connectable option */ str = g_key_file_get_string(config, "Headset", "FastConnectable", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else { fast_connectable = strcmp(str, "true") == 0; if (fast_connectable) manager_set_fast_connectable(FALSE); g_free(str); } return ag.features; } static gboolean hs_dc_timeout(struct audio_device *dev) { headset_set_state(dev, HEADSET_STATE_DISCONNECTED); return FALSE; } gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id) { struct headset *hs = dev->headset; struct pending_connect *p = hs->pending; GSList *l; struct connect_cb *cb = NULL; if (!p) return FALSE; for (l = p->callbacks; l != NULL; l = l->next) { struct connect_cb *tmp = l->data; if (tmp->id == id) { cb = tmp; break; } } if (!cb) return FALSE; p->callbacks = g_slist_remove(p->callbacks, cb); g_free(cb); if (p->callbacks || p->msg) return TRUE; if (hs->auto_dc) { if (hs->rfcomm) hs->dc_timer = g_timeout_add_seconds(DC_TIMEOUT, (GSourceFunc) hs_dc_timeout, dev); else headset_set_state(dev, HEADSET_STATE_DISCONNECTED); } return TRUE; } static gboolean dummy_connect_complete(struct audio_device *dev) { pending_connect_finalize(dev); return FALSE; } unsigned int headset_request_stream(struct audio_device *dev, headset_stream_cb_t cb, void *user_data) { struct headset *hs = dev->headset; unsigned int id; if (hs->state == HEADSET_STATE_PLAYING) { id = connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data); g_idle_add((GSourceFunc) dummy_connect_complete, dev); return id; } if (hs->dc_timer) { g_source_remove(hs->dc_timer); hs->dc_timer = 0; } if (hs->state == HEADSET_STATE_CONNECTING || hs->state == HEADSET_STATE_PLAY_IN_PROGRESS) return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data); if (hs->rfcomm == NULL) { if (rfcomm_connect(dev, cb, user_data, &id) < 0) return 0; hs->auto_dc = TRUE; } else if (sco_connect(dev, cb, user_data, &id) < 0) return 0; hs->pending->target_state = HEADSET_STATE_PLAYING; return id; } unsigned int headset_config_stream(struct audio_device *dev, gboolean auto_dc, headset_stream_cb_t cb, void *user_data) { struct headset *hs = dev->headset; unsigned int id = 0; if (hs->dc_timer) { g_source_remove(hs->dc_timer); hs->dc_timer = 0; } if (hs->state == HEADSET_STATE_CONNECTING) return connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data); if (hs->rfcomm) goto done; if (rfcomm_connect(dev, cb, user_data, &id) < 0) return 0; hs->auto_dc = auto_dc; hs->pending->target_state = HEADSET_STATE_CONNECTED; return id; done: id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data); g_idle_add((GSourceFunc) dummy_connect_complete, dev); return id; } unsigned int headset_suspend_stream(struct audio_device *dev, headset_stream_cb_t cb, void *user_data) { struct headset *hs = dev->headset; unsigned int id; int sock; if (hs->state == HEADSET_STATE_DISCONNECTED || hs->state == HEADSET_STATE_CONNECTING) return 0; if (hs->dc_timer) { g_source_remove(hs->dc_timer); hs->dc_timer = 0; } if (hs->sco) { sock = g_io_channel_unix_get_fd(hs->sco); /* shutdown but leave the socket open and wait for hup */ shutdown(sock, SHUT_RDWR); } else { headset_set_state(dev, HEADSET_STATE_CONNECTED); g_idle_add((GSourceFunc) dummy_connect_complete, dev); } id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data); return id; } gboolean headset_get_hfp_active(struct audio_device *dev) { struct headset *hs = dev->headset; return hs->hfp_active; } void headset_set_hfp_active(struct audio_device *dev, gboolean active) { struct headset *hs = dev->headset; hs->hfp_active = active; } gboolean headset_get_rfcomm_initiator(struct audio_device *dev) { struct headset *hs = dev->headset; return hs->rfcomm_initiator; } void headset_set_rfcomm_initiator(struct audio_device *dev, gboolean initiator) { struct headset *hs = dev->headset; hs->rfcomm_initiator = initiator; } GIOChannel *headset_get_rfcomm(struct audio_device *dev) { struct headset *hs = dev->headset; return hs->tmp_rfcomm; } int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io) { struct headset *hs = dev->headset; if (hs->tmp_rfcomm) return -EALREADY; hs->tmp_rfcomm = g_io_channel_ref(io); return 0; } int headset_connect_sco(struct audio_device *dev, GIOChannel *io) { struct headset *hs = dev->headset; struct headset_slc *slc = hs->slc; if (hs->sco) return -EISCONN; hs->sco = g_io_channel_ref(io); if (slc->pending_ring) { ring_timer_cb(NULL); ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb, NULL); slc->pending_ring = FALSE; } return 0; } void headset_set_state(struct audio_device *dev, headset_state_t state) { struct headset *hs = dev->headset; struct headset_slc *slc = hs->slc; gboolean value; const char *state_str; headset_state_t old_state = hs->state; GSList *l; if (old_state == state) return; state_str = state2str(state); switch (state) { case HEADSET_STATE_DISCONNECTED: value = FALSE; close_sco(dev); headset_close_rfcomm(dev); emit_property_changed(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "State", DBUS_TYPE_STRING, &state_str); g_dbus_emit_signal(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); if (hs->state > HEADSET_STATE_CONNECTING) { emit_property_changed(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &value); telephony_device_disconnected(dev); } active_devices = g_slist_remove(active_devices, dev); break; case HEADSET_STATE_CONNECTING: emit_property_changed(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "State", DBUS_TYPE_STRING, &state_str); break; case HEADSET_STATE_CONNECTED: close_sco(dev); if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS) emit_property_changed(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "State", DBUS_TYPE_STRING, &state_str); if (hs->state < state) { if (ag.features & AG_FEATURE_INBAND_RINGTONE) slc->inband_ring = TRUE; else slc->inband_ring = FALSE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Connected", DBUS_TYPE_INVALID); value = TRUE; emit_property_changed(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &value); active_devices = g_slist_append(active_devices, dev); telephony_device_connected(dev); } else if (hs->state == HEADSET_STATE_PLAYING) { value = FALSE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Stopped", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Playing", DBUS_TYPE_BOOLEAN, &value); } break; case HEADSET_STATE_PLAY_IN_PROGRESS: break; case HEADSET_STATE_PLAYING: value = TRUE; emit_property_changed(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "State", DBUS_TYPE_STRING, &state_str); /* Do not watch HUP since we need to know when the link is really disconnected */ hs->sco_id = g_io_add_watch(hs->sco, G_IO_ERR | G_IO_NVAL, (GIOFunc) sco_cb, dev); g_dbus_emit_signal(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Playing", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_HEADSET_INTERFACE, "Playing", DBUS_TYPE_BOOLEAN, &value); if (slc->sp_gain >= 0) headset_send(hs, "\r\n+VGS=%u\r\n", slc->sp_gain); if (slc->mic_gain >= 0) headset_send(hs, "\r\n+VGM=%u\r\n", slc->mic_gain); break; } hs->state = state; DBG("State changed %s: %s -> %s", dev->path, str_state[old_state], str_state[state]); for (l = headset_callbacks; l != NULL; l = l->next) { struct headset_state_callback *cb = l->data; cb->cb(dev, old_state, state, cb->user_data); } } headset_state_t headset_get_state(struct audio_device *dev) { struct headset *hs = dev->headset; return hs->state; } int headset_get_channel(struct audio_device *dev) { struct headset *hs = dev->headset; return hs->rfcomm_ch; } gboolean headset_is_active(struct audio_device *dev) { struct headset *hs = dev->headset; if (hs->state != HEADSET_STATE_DISCONNECTED) return TRUE; return FALSE; } headset_lock_t headset_get_lock(struct audio_device *dev) { struct headset *hs = dev->headset; return hs->lock; } gboolean headset_lock(struct audio_device *dev, headset_lock_t lock) { struct headset *hs = dev->headset; if (hs->lock & lock) return FALSE; hs->lock |= lock; return TRUE; } gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock) { struct headset *hs = dev->headset; if (!(hs->lock & lock)) return FALSE; hs->lock &= ~lock; if (hs->lock) return TRUE; if (hs->state == HEADSET_STATE_PLAYING) headset_set_state(dev, HEADSET_STATE_CONNECTED); if (hs->auto_dc) { if (hs->state == HEADSET_STATE_CONNECTED) hs->dc_timer = g_timeout_add_seconds(DC_TIMEOUT, (GSourceFunc) hs_dc_timeout, dev); else headset_set_state(dev, HEADSET_STATE_DISCONNECTED); } return TRUE; } gboolean headset_suspend(struct audio_device *dev, void *data) { return TRUE; } gboolean headset_play(struct audio_device *dev, void *data) { return TRUE; } int headset_get_sco_fd(struct audio_device *dev) { struct headset *hs = dev->headset; if (!hs->sco) return -1; return g_io_channel_unix_get_fd(hs->sco); } gboolean headset_get_nrec(struct audio_device *dev) { struct headset *hs = dev->headset; if (!hs->slc) return TRUE; return hs->slc->nrec; } unsigned int headset_add_nrec_cb(struct audio_device *dev, headset_nrec_cb cb, void *user_data) { struct headset *hs = dev->headset; struct headset_nrec_callback *nrec_cb; static unsigned int id = 0; nrec_cb = g_new(struct headset_nrec_callback, 1); nrec_cb->cb = cb; nrec_cb->user_data = user_data; nrec_cb->id = ++id; hs->nrec_cbs = g_slist_prepend(hs->nrec_cbs, nrec_cb); return nrec_cb->id; } gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id) { struct headset *hs = dev->headset; GSList *l; for (l = hs->nrec_cbs; l != NULL; l = l->next) { struct headset_nrec_callback *cb = l->data; if (cb && cb->id == id) { hs->nrec_cbs = g_slist_remove(hs->nrec_cbs, cb); g_free(cb); return TRUE; } } return FALSE; } gboolean headset_get_inband(struct audio_device *dev) { struct headset *hs = dev->headset; if (!hs->slc) return TRUE; return hs->slc->inband_ring; } gboolean headset_get_sco_hci(struct audio_device *dev) { return sco_hci; } void headset_shutdown(struct audio_device *dev) { struct pending_connect *p = dev->headset->pending; if (p && p->msg) error_connect_failed(dev->conn, p->msg, ECANCELED); pending_connect_finalize(dev); headset_set_state(dev, HEADSET_STATE_DISCONNECTED); } int telephony_event_ind(int index) { if (!active_devices) return -ENODEV; if (!ag.er_ind) { DBG("telephony_report_event called but events are disabled"); return -EINVAL; } send_foreach_headset(active_devices, hfp_cmp, "\r\n+CIEV: %d,%d\r\n", index + 1, ag.indicators[index].val); return 0; } int telephony_response_and_hold_ind(int rh) { if (!active_devices) return -ENODEV; ag.rh = rh; /* If we aren't in any response and hold state don't send anything */ if (ag.rh < 0) return 0; send_foreach_headset(active_devices, hfp_cmp, "\r\n+BTRH: %d\r\n", ag.rh); return 0; } int telephony_incoming_call_ind(const char *number, int type) { struct audio_device *dev; struct headset *hs; struct headset_slc *slc; if (fast_connectable) manager_set_fast_connectable(TRUE); if (!active_devices) return -ENODEV; /* Get the latest connected device */ dev = active_devices->data; hs = dev->headset; slc = hs->slc; if (ag.ring_timer) { DBG("telephony_incoming_call_ind: already calling"); return -EBUSY; } /* With HSP 1.2 the RING messages should *not* be sent if inband * ringtone is being used */ if (!hs->hfp_active && slc->inband_ring) return 0; g_free(ag.number); ag.number = g_strdup(number); ag.number_type = type; if (slc->inband_ring && hs->hfp_active && hs->state != HEADSET_STATE_PLAYING) { slc->pending_ring = TRUE; return 0; } ring_timer_cb(NULL); ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb, NULL); return 0; } int telephony_calling_stopped_ind(void) { struct audio_device *dev; if (fast_connectable) manager_set_fast_connectable(FALSE); if (ag.ring_timer) { g_source_remove(ag.ring_timer); ag.ring_timer = 0; } if (!active_devices) return 0; /* In case SCO isn't fully up yet */ dev = active_devices->data; if (!dev->headset->slc->pending_ring && !ag.ring_timer) return -EINVAL; dev->headset->slc->pending_ring = FALSE; return 0; } int telephony_ready_ind(uint32_t features, const struct indicator *indicators, int rh, const char *chld) { ag.telephony_ready = TRUE; ag.features = features; ag.indicators = indicators; ag.rh = rh; ag.chld = chld; DBG("Telephony plugin initialized"); print_ag_features(ag.features); return 0; } int telephony_deinit(void) { g_free(ag.number); memset(&ag, 0, sizeof(ag)); ag.er_mode = 3; ag.rh = BTRH_NOT_SUPPORTED; DBG("Telephony deinitialized"); return 0; } int telephony_list_current_call_ind(int idx, int dir, int status, int mode, int mprty, const char *number, int type) { if (!active_devices) return -ENODEV; if (number && strlen(number) > 0) send_foreach_headset(active_devices, hfp_cmp, "\r\n+CLCC: %d,%d,%d,%d,%d,\"%s\",%d\r\n", idx, dir, status, mode, mprty, number, type); else send_foreach_headset(active_devices, hfp_cmp, "\r\n+CLCC: %d,%d,%d,%d,%d\r\n", idx, dir, status, mode, mprty); return 0; } int telephony_subscriber_number_ind(const char *number, int type, int service) { if (!active_devices) return -ENODEV; send_foreach_headset(active_devices, hfp_cmp, "\r\n+CNUM: ,%s,%d,,%d\r\n", number, type, service); return 0; } static int cwa_cmp(struct headset *hs) { if (!hs->hfp_active) return -1; if (hs->slc->cwa_enabled) return 0; else return -1; } int telephony_call_waiting_ind(const char *number, int type) { if (!active_devices) return -ENODEV; send_foreach_headset(active_devices, cwa_cmp, "\r\n+CCWA: \"%s\",%d\r\n", number, type); return 0; } unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data) { struct headset_state_callback *state_cb; static unsigned int id = 0; state_cb = g_new(struct headset_state_callback, 1); state_cb->cb = cb; state_cb->user_data = user_data; state_cb->id = ++id; headset_callbacks = g_slist_append(headset_callbacks, state_cb); return state_cb->id; } gboolean headset_remove_state_cb(unsigned int id) { GSList *l; for (l = headset_callbacks; l != NULL; l = l->next) { struct headset_state_callback *cb = l->data; if (cb && cb->id == id) { headset_callbacks = g_slist_remove(headset_callbacks, cb); g_free(cb); return TRUE; } } return FALSE; } bluez-4.101/audio/headset.h0000644000000000000000000000771211766125764012444 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define AUDIO_HEADSET_INTERFACE "org.bluez.Headset" #define DEFAULT_HS_AG_CHANNEL 12 #define DEFAULT_HF_AG_CHANNEL 13 typedef enum { HEADSET_STATE_DISCONNECTED, HEADSET_STATE_CONNECTING, HEADSET_STATE_CONNECTED, HEADSET_STATE_PLAY_IN_PROGRESS, HEADSET_STATE_PLAYING } headset_state_t; typedef enum { HEADSET_LOCK_READ = 1, HEADSET_LOCK_WRITE = 1 << 1, } headset_lock_t; typedef void (*headset_state_cb) (struct audio_device *dev, headset_state_t old_state, headset_state_t new_state, void *user_data); typedef void (*headset_nrec_cb) (struct audio_device *dev, gboolean nrec, void *user_data); unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data); gboolean headset_remove_state_cb(unsigned int id); typedef void (*headset_stream_cb_t) (struct audio_device *dev, void *user_data); void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data); GIOChannel *headset_get_rfcomm(struct audio_device *dev); struct headset *headset_init(struct audio_device *dev, uint16_t svc, const char *uuidstr); void headset_unregister(struct audio_device *dev); uint32_t headset_config_init(GKeyFile *config); void headset_update(struct audio_device *dev, uint16_t svc, const char *uuidstr); unsigned int headset_config_stream(struct audio_device *dev, gboolean auto_dc, headset_stream_cb_t cb, void *user_data); unsigned int headset_request_stream(struct audio_device *dev, headset_stream_cb_t cb, void *user_data); unsigned int headset_suspend_stream(struct audio_device *dev, headset_stream_cb_t cb, void *user_data); gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id); gboolean headset_get_hfp_active(struct audio_device *dev); void headset_set_hfp_active(struct audio_device *dev, gboolean active); gboolean headset_get_rfcomm_initiator(struct audio_device *dev); void headset_set_rfcomm_initiator(struct audio_device *dev, gboolean initiator); int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *chan); int headset_connect_sco(struct audio_device *dev, GIOChannel *io); headset_state_t headset_get_state(struct audio_device *dev); void headset_set_state(struct audio_device *dev, headset_state_t state); int headset_get_channel(struct audio_device *dev); int headset_get_sco_fd(struct audio_device *dev); gboolean headset_get_nrec(struct audio_device *dev); unsigned int headset_add_nrec_cb(struct audio_device *dev, headset_nrec_cb cb, void *user_data); gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id); gboolean headset_get_inband(struct audio_device *dev); gboolean headset_get_sco_hci(struct audio_device *dev); gboolean headset_is_active(struct audio_device *dev); headset_lock_t headset_get_lock(struct audio_device *dev); gboolean headset_lock(struct audio_device *dev, headset_lock_t lock); gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock); gboolean headset_suspend(struct audio_device *dev, void *data); gboolean headset_play(struct audio_device *dev, void *data); void headset_shutdown(struct audio_device *dev); bluez-4.101/audio/gstavdtpsink.c0000644000000000000000000014505411766125764013545 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "ipc.h" #include "rtp.h" #include "a2dp-codecs.h" #include "gstpragma.h" #include "gstavdtpsink.h" GST_DEBUG_CATEGORY_STATIC(avdtp_sink_debug); #define GST_CAT_DEFAULT avdtp_sink_debug #define BUFFER_SIZE 2048 #define TEMPLATE_MAX_BITPOOL 64 #define CRC_PROTECTED 1 #define CRC_UNPROTECTED 0 #define DEFAULT_AUTOCONNECT TRUE #define GST_AVDTP_SINK_MUTEX_LOCK(s) G_STMT_START { \ g_mutex_lock(s->sink_lock); \ } G_STMT_END #define GST_AVDTP_SINK_MUTEX_UNLOCK(s) G_STMT_START { \ g_mutex_unlock(s->sink_lock); \ } G_STMT_END struct bluetooth_data { struct bt_get_capabilities_rsp *caps; /* Bluetooth device caps */ guint link_mtu; DBusConnection *conn; guint8 codec; /* Bluetooth transport configuration */ gchar *uuid; guint8 *config; gint config_size; gchar buffer[BUFFER_SIZE]; /* Codec transfer buffer */ }; #define IS_SBC(n) (strcmp((n), "audio/x-sbc") == 0) #define IS_MPEG_AUDIO(n) (strcmp((n), "audio/mpeg") == 0) enum { PROP_0, PROP_DEVICE, PROP_AUTOCONNECT, PROP_TRANSPORT }; GST_BOILERPLATE(GstAvdtpSink, gst_avdtp_sink, GstBaseSink, GST_TYPE_BASE_SINK); static const GstElementDetails avdtp_sink_details = GST_ELEMENT_DETAILS("Bluetooth AVDTP sink", "Sink/Audio", "Plays audio to an A2DP device", "Marcel Holtmann "); static GstStaticPadTemplate avdtp_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("application/x-rtp, " "media = (string) \"audio\"," "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " "clock-rate = (int) { 16000, 32000, " "44100, 48000 }, " "encoding-name = (string) \"SBC\"; " "application/x-rtp, " "media = (string) \"audio\", " "payload = (int) " GST_RTP_PAYLOAD_MPA_STRING ", " "clock-rate = (int) 90000; " "application/x-rtp, " "media = (string) \"audio\", " "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " "clock-rate = (int) 90000, " "encoding-name = (string) \"MPA\"" )); static int gst_avdtp_sink_audioservice_send(GstAvdtpSink *self, const bt_audio_msg_header_t *msg); static int gst_avdtp_sink_audioservice_expect(GstAvdtpSink *self, bt_audio_msg_header_t *outmsg, guint8 expected_name); static void gst_avdtp_sink_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&avdtp_sink_factory)); gst_element_class_set_details(element_class, &avdtp_sink_details); } static void gst_avdtp_sink_transport_release(GstAvdtpSink *self) { DBusMessage *msg; const char *access_type = "w"; msg = dbus_message_new_method_call("org.bluez", self->transport, "org.bluez.MediaTransport", "Release"); dbus_message_append_args(msg, DBUS_TYPE_STRING, &access_type, DBUS_TYPE_INVALID); dbus_connection_send(self->data->conn, msg, NULL); dbus_message_unref(msg); } static gboolean gst_avdtp_sink_stop(GstBaseSink *basesink) { GstAvdtpSink *self = GST_AVDTP_SINK(basesink); GST_INFO_OBJECT(self, "stop"); if (self->watch_id != 0) { g_source_remove(self->watch_id); self->watch_id = 0; } if (self->server) { bt_audio_service_close(g_io_channel_unix_get_fd(self->server)); g_io_channel_unref(self->server); self->server = NULL; } if (self->stream) { g_io_channel_shutdown(self->stream, TRUE, NULL); g_io_channel_unref(self->stream); self->stream = NULL; } if (self->data) { if (self->transport) gst_avdtp_sink_transport_release(self); if (self->data->conn) dbus_connection_unref(self->data->conn); g_free(self->data); self->data = NULL; } if (self->stream_caps) { gst_caps_unref(self->stream_caps); self->stream_caps = NULL; } if (self->dev_caps) { gst_caps_unref(self->dev_caps); self->dev_caps = NULL; } return TRUE; } static void gst_avdtp_sink_finalize(GObject *object) { GstAvdtpSink *self = GST_AVDTP_SINK(object); if (self->data) gst_avdtp_sink_stop(GST_BASE_SINK(self)); if (self->device) g_free(self->device); if (self->transport) g_free(self->transport); g_mutex_free(self->sink_lock); G_OBJECT_CLASS(parent_class)->finalize(object); } static void gst_avdtp_sink_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstAvdtpSink *sink = GST_AVDTP_SINK(object); switch (prop_id) { case PROP_DEVICE: if (sink->device) g_free(sink->device); sink->device = g_value_dup_string(value); break; case PROP_AUTOCONNECT: sink->autoconnect = g_value_get_boolean(value); break; case PROP_TRANSPORT: if (sink->transport) g_free(sink->transport); sink->transport = g_value_dup_string(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_avdtp_sink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstAvdtpSink *sink = GST_AVDTP_SINK(object); switch (prop_id) { case PROP_DEVICE: g_value_set_string(value, sink->device); break; case PROP_AUTOCONNECT: g_value_set_boolean(value, sink->autoconnect); break; case PROP_TRANSPORT: g_value_set_string(value, sink->transport); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static gint gst_avdtp_sink_bluetooth_recvmsg_fd(GstAvdtpSink *sink) { int err, ret; ret = bt_audio_service_get_data_fd( g_io_channel_unix_get_fd(sink->server)); if (ret < 0) { err = -errno; GST_ERROR_OBJECT(sink, "Unable to receive fd: %s (%d)", strerror(-err), -err); return err; } sink->stream = g_io_channel_unix_new(ret); g_io_channel_set_encoding(sink->stream, NULL, NULL); GST_DEBUG_OBJECT(sink, "stream_fd=%d", ret); return 0; } static codec_capabilities_t *gst_avdtp_find_caps(GstAvdtpSink *sink, uint8_t codec_type) { struct bt_get_capabilities_rsp *rsp = sink->data->caps; codec_capabilities_t *codec = (void *) rsp->data; int bytes_left = rsp->h.length - sizeof(*rsp); while (bytes_left > 0) { if ((codec->type == codec_type) && !(codec->lock & BT_WRITE_LOCK)) break; bytes_left -= codec->length; codec = (void *) codec + codec->length; } if (bytes_left <= 0) return NULL; return codec; } static gboolean gst_avdtp_sink_init_sbc_pkt_conf(GstAvdtpSink *sink, GstCaps *caps, sbc_capabilities_t *pkt) { sbc_capabilities_t *cfg; const GValue *value = NULL; const char *pref, *name; gint rate, subbands, blocks; GstStructure *structure = gst_caps_get_structure(caps, 0); cfg = (void *) gst_avdtp_find_caps(sink, BT_A2DP_SBC_SINK); name = gst_structure_get_name(structure); if (!(IS_SBC(name))) { GST_ERROR_OBJECT(sink, "Unexpected format %s, " "was expecting sbc", name); return FALSE; } value = gst_structure_get_value(structure, "rate"); rate = g_value_get_int(value); if (rate == 44100) cfg->frequency = BT_SBC_SAMPLING_FREQ_44100; else if (rate == 48000) cfg->frequency = BT_SBC_SAMPLING_FREQ_48000; else if (rate == 32000) cfg->frequency = BT_SBC_SAMPLING_FREQ_32000; else if (rate == 16000) cfg->frequency = BT_SBC_SAMPLING_FREQ_16000; else { GST_ERROR_OBJECT(sink, "Invalid rate while setting caps"); return FALSE; } value = gst_structure_get_value(structure, "mode"); pref = g_value_get_string(value); if (strcmp(pref, "mono") == 0) cfg->channel_mode = BT_A2DP_CHANNEL_MODE_MONO; else if (strcmp(pref, "dual") == 0) cfg->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL; else if (strcmp(pref, "stereo") == 0) cfg->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO; else if (strcmp(pref, "joint") == 0) cfg->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO; else { GST_ERROR_OBJECT(sink, "Invalid mode %s", pref); return FALSE; } value = gst_structure_get_value(structure, "allocation"); pref = g_value_get_string(value); if (strcmp(pref, "loudness") == 0) cfg->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS; else if (strcmp(pref, "snr") == 0) cfg->allocation_method = BT_A2DP_ALLOCATION_SNR; else { GST_ERROR_OBJECT(sink, "Invalid allocation: %s", pref); return FALSE; } value = gst_structure_get_value(structure, "subbands"); subbands = g_value_get_int(value); if (subbands == 8) cfg->subbands = BT_A2DP_SUBBANDS_8; else if (subbands == 4) cfg->subbands = BT_A2DP_SUBBANDS_4; else { GST_ERROR_OBJECT(sink, "Invalid subbands %d", subbands); return FALSE; } value = gst_structure_get_value(structure, "blocks"); blocks = g_value_get_int(value); if (blocks == 16) cfg->block_length = BT_A2DP_BLOCK_LENGTH_16; else if (blocks == 12) cfg->block_length = BT_A2DP_BLOCK_LENGTH_12; else if (blocks == 8) cfg->block_length = BT_A2DP_BLOCK_LENGTH_8; else if (blocks == 4) cfg->block_length = BT_A2DP_BLOCK_LENGTH_4; else { GST_ERROR_OBJECT(sink, "Invalid blocks %d", blocks); return FALSE; } value = gst_structure_get_value(structure, "bitpool"); cfg->max_bitpool = cfg->min_bitpool = g_value_get_int(value); memcpy(pkt, cfg, sizeof(*pkt)); return TRUE; } static gboolean gst_avdtp_sink_conf_recv_stream_fd( GstAvdtpSink *self) { struct bluetooth_data *data = self->data; gint ret; GError *gerr = NULL; GIOStatus status; GIOFlags flags; int fd; /* Proceed if stream was already acquired */ if (self->stream != NULL) goto proceed; ret = gst_avdtp_sink_bluetooth_recvmsg_fd(self); if (ret < 0) return FALSE; if (!self->stream) { GST_ERROR_OBJECT(self, "Error while configuring device: " "could not acquire audio socket"); return FALSE; } proceed: /* set stream socket to nonblock */ GST_LOG_OBJECT(self, "setting stream socket to nonblock"); flags = g_io_channel_get_flags(self->stream); flags |= G_IO_FLAG_NONBLOCK; status = g_io_channel_set_flags(self->stream, flags, &gerr); if (status != G_IO_STATUS_NORMAL) { if (gerr) GST_WARNING_OBJECT(self, "Error while " "setting server socket to nonblock: " "%s", gerr->message); else GST_WARNING_OBJECT(self, "Error while " "setting server " "socket to nonblock"); } fd = g_io_channel_unix_get_fd(self->stream); /* It is possible there is some outstanding data in the pipe - we have to empty it */ GST_LOG_OBJECT(self, "emptying stream pipe"); while (1) { ssize_t bread = read(fd, data->buffer, data->link_mtu); if (bread <= 0) break; } /* set stream socket to block */ GST_LOG_OBJECT(self, "setting stream socket to block"); flags = g_io_channel_get_flags(self->stream); flags &= ~G_IO_FLAG_NONBLOCK; status = g_io_channel_set_flags(self->stream, flags, &gerr); if (status != G_IO_STATUS_NORMAL) { if (gerr) GST_WARNING_OBJECT(self, "Error while " "setting server socket to block:" "%s", gerr->message); else GST_WARNING_OBJECT(self, "Error while " "setting server " "socket to block"); } memset(data->buffer, 0, sizeof(data->buffer)); return TRUE; } static gboolean server_callback(GIOChannel *chan, GIOCondition cond, gpointer data) { if (cond & G_IO_HUP || cond & G_IO_NVAL) return FALSE; else if (cond & G_IO_ERR) GST_WARNING_OBJECT(GST_AVDTP_SINK(data), "Untreated callback G_IO_ERR"); return TRUE; } static GstStructure *gst_avdtp_sink_parse_sbc_caps( GstAvdtpSink *self, sbc_capabilities_t *sbc) { GstStructure *structure; GValue *value; GValue *list; gboolean mono, stereo; if (sbc == NULL) return NULL; structure = gst_structure_empty_new("audio/x-sbc"); value = g_value_init(g_new0(GValue, 1), G_TYPE_STRING); /* mode */ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) { g_value_set_static_string(value, "mono"); gst_value_list_prepend_value(list, value); } if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) { g_value_set_static_string(value, "stereo"); gst_value_list_prepend_value(list, value); } if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) { g_value_set_static_string(value, "dual"); gst_value_list_prepend_value(list, value); } if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) { g_value_set_static_string(value, "joint"); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "mode", list); g_free(list); list = NULL; } /* subbands */ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); value = g_value_init(value, G_TYPE_INT); if (sbc->subbands & BT_A2DP_SUBBANDS_4) { g_value_set_int(value, 4); gst_value_list_prepend_value(list, value); } if (sbc->subbands & BT_A2DP_SUBBANDS_8) { g_value_set_int(value, 8); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "subbands", list); g_free(list); list = NULL; } /* blocks */ value = g_value_init(value, G_TYPE_INT); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_16) { g_value_set_int(value, 16); gst_value_list_prepend_value(list, value); } if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_12) { g_value_set_int(value, 12); gst_value_list_prepend_value(list, value); } if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_8) { g_value_set_int(value, 8); gst_value_list_prepend_value(list, value); } if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_4) { g_value_set_int(value, 4); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "blocks", list); g_free(list); list = NULL; } /* allocation */ g_value_init(value, G_TYPE_STRING); list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST); if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) { g_value_set_static_string(value, "loudness"); gst_value_list_prepend_value(list, value); } if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) { g_value_set_static_string(value, "snr"); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "allocation", list); g_free(list); list = NULL; } /* rate */ g_value_init(value, G_TYPE_INT); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (sbc->frequency & BT_SBC_SAMPLING_FREQ_48000) { g_value_set_int(value, 48000); gst_value_list_prepend_value(list, value); } if (sbc->frequency & BT_SBC_SAMPLING_FREQ_44100) { g_value_set_int(value, 44100); gst_value_list_prepend_value(list, value); } if (sbc->frequency & BT_SBC_SAMPLING_FREQ_32000) { g_value_set_int(value, 32000); gst_value_list_prepend_value(list, value); } if (sbc->frequency & BT_SBC_SAMPLING_FREQ_16000) { g_value_set_int(value, 16000); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "rate", list); g_free(list); list = NULL; } /* bitpool */ value = g_value_init(value, GST_TYPE_INT_RANGE); gst_value_set_int_range(value, MIN(sbc->min_bitpool, TEMPLATE_MAX_BITPOOL), MIN(sbc->max_bitpool, TEMPLATE_MAX_BITPOOL)); gst_structure_set_value(structure, "bitpool", value); g_value_unset(value); /* channels */ mono = FALSE; stereo = FALSE; if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) mono = TRUE; if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) || (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) || (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)) stereo = TRUE; if (mono && stereo) { g_value_init(value, GST_TYPE_INT_RANGE); gst_value_set_int_range(value, 1, 2); } else { g_value_init(value, G_TYPE_INT); if (mono) g_value_set_int(value, 1); else if (stereo) g_value_set_int(value, 2); else { GST_ERROR_OBJECT(self, "Unexpected number of channels"); g_value_set_int(value, 0); } } gst_structure_set_value(structure, "channels", value); g_free(value); return structure; } static GstStructure *gst_avdtp_sink_parse_mpeg_caps( GstAvdtpSink *self, mpeg_capabilities_t *mpeg) { GstStructure *structure; GValue *value; GValue *list; gboolean valid_layer = FALSE; gboolean mono, stereo; if (!mpeg) return NULL; GST_LOG_OBJECT(self, "parsing mpeg caps"); structure = gst_structure_empty_new("audio/mpeg"); value = g_new0(GValue, 1); g_value_init(value, G_TYPE_INT); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); g_value_set_int(value, 1); gst_value_list_prepend_value(list, value); g_value_set_int(value, 2); gst_value_list_prepend_value(list, value); gst_structure_set_value(structure, "mpegversion", list); g_free(list); /* layer */ GST_LOG_OBJECT(self, "setting mpeg layer"); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (mpeg->layer & BT_MPEG_LAYER_1) { g_value_set_int(value, 1); gst_value_list_prepend_value(list, value); valid_layer = TRUE; } if (mpeg->layer & BT_MPEG_LAYER_2) { g_value_set_int(value, 2); gst_value_list_prepend_value(list, value); valid_layer = TRUE; } if (mpeg->layer & BT_MPEG_LAYER_3) { g_value_set_int(value, 3); gst_value_list_prepend_value(list, value); valid_layer = TRUE; } if (list) { gst_structure_set_value(structure, "layer", list); g_free(list); list = NULL; } if (!valid_layer) { gst_structure_free(structure); g_free(value); return NULL; } /* rate */ GST_LOG_OBJECT(self, "setting mpeg rate"); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_48000) { g_value_set_int(value, 48000); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_44100) { g_value_set_int(value, 44100); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_32000) { g_value_set_int(value, 32000); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_24000) { g_value_set_int(value, 24000); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_22050) { g_value_set_int(value, 22050); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_16000) { g_value_set_int(value, 16000); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "rate", list); g_free(list); list = NULL; } /* channels */ GST_LOG_OBJECT(self, "setting mpeg channels"); mono = FALSE; stereo = FALSE; if (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) mono = TRUE; if ((mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) || (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) || (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)) stereo = TRUE; if (mono && stereo) { g_value_init(value, GST_TYPE_INT_RANGE); gst_value_set_int_range(value, 1, 2); } else { g_value_init(value, G_TYPE_INT); if (mono) g_value_set_int(value, 1); else if (stereo) g_value_set_int(value, 2); else { GST_ERROR_OBJECT(self, "Unexpected number of channels"); g_value_set_int(value, 0); } } gst_structure_set_value(structure, "channels", value); g_free(value); return structure; } static GstStructure *gst_avdtp_sink_parse_sbc_raw(GstAvdtpSink *self) { a2dp_sbc_t *sbc = (a2dp_sbc_t *) self->data->config; GstStructure *structure; GValue *value; GValue *list; gboolean mono, stereo; structure = gst_structure_empty_new("audio/x-sbc"); value = g_value_init(g_new0(GValue, 1), G_TYPE_STRING); /* mode */ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) { g_value_set_static_string(value, "mono"); gst_value_list_prepend_value(list, value); } if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) { g_value_set_static_string(value, "stereo"); gst_value_list_prepend_value(list, value); } if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) { g_value_set_static_string(value, "dual"); gst_value_list_prepend_value(list, value); } if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) { g_value_set_static_string(value, "joint"); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "mode", list); g_free(list); list = NULL; } /* subbands */ list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); value = g_value_init(value, G_TYPE_INT); if (sbc->subbands & BT_A2DP_SUBBANDS_4) { g_value_set_int(value, 4); gst_value_list_prepend_value(list, value); } if (sbc->subbands & BT_A2DP_SUBBANDS_8) { g_value_set_int(value, 8); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "subbands", list); g_free(list); list = NULL; } /* blocks */ value = g_value_init(value, G_TYPE_INT); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_16) { g_value_set_int(value, 16); gst_value_list_prepend_value(list, value); } if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_12) { g_value_set_int(value, 12); gst_value_list_prepend_value(list, value); } if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_8) { g_value_set_int(value, 8); gst_value_list_prepend_value(list, value); } if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_4) { g_value_set_int(value, 4); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "blocks", list); g_free(list); list = NULL; } /* allocation */ g_value_init(value, G_TYPE_STRING); list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST); if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) { g_value_set_static_string(value, "loudness"); gst_value_list_prepend_value(list, value); } if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) { g_value_set_static_string(value, "snr"); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "allocation", list); g_free(list); list = NULL; } /* rate */ g_value_init(value, G_TYPE_INT); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (sbc->frequency & BT_SBC_SAMPLING_FREQ_48000) { g_value_set_int(value, 48000); gst_value_list_prepend_value(list, value); } if (sbc->frequency & BT_SBC_SAMPLING_FREQ_44100) { g_value_set_int(value, 44100); gst_value_list_prepend_value(list, value); } if (sbc->frequency & BT_SBC_SAMPLING_FREQ_32000) { g_value_set_int(value, 32000); gst_value_list_prepend_value(list, value); } if (sbc->frequency & BT_SBC_SAMPLING_FREQ_16000) { g_value_set_int(value, 16000); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "rate", list); g_free(list); list = NULL; } /* bitpool */ value = g_value_init(value, GST_TYPE_INT_RANGE); gst_value_set_int_range(value, MIN(sbc->min_bitpool, TEMPLATE_MAX_BITPOOL), MIN(sbc->max_bitpool, TEMPLATE_MAX_BITPOOL)); gst_structure_set_value(structure, "bitpool", value); g_value_unset(value); /* channels */ mono = FALSE; stereo = FALSE; if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) mono = TRUE; if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) || (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) || (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)) stereo = TRUE; if (mono && stereo) { g_value_init(value, GST_TYPE_INT_RANGE); gst_value_set_int_range(value, 1, 2); } else { g_value_init(value, G_TYPE_INT); if (mono) g_value_set_int(value, 1); else if (stereo) g_value_set_int(value, 2); else { GST_ERROR_OBJECT(self, "Unexpected number of channels"); g_value_set_int(value, 0); } } gst_structure_set_value(structure, "channels", value); g_free(value); return structure; } static GstStructure *gst_avdtp_sink_parse_mpeg_raw(GstAvdtpSink *self) { a2dp_mpeg_t *mpeg = (a2dp_mpeg_t *) self->data->config; GstStructure *structure; GValue *value; GValue *list; gboolean valid_layer = FALSE; gboolean mono, stereo; GST_LOG_OBJECT(self, "parsing mpeg caps"); structure = gst_structure_empty_new("audio/mpeg"); value = g_new0(GValue, 1); g_value_init(value, G_TYPE_INT); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); g_value_set_int(value, 1); gst_value_list_prepend_value(list, value); g_value_set_int(value, 2); gst_value_list_prepend_value(list, value); gst_structure_set_value(structure, "mpegversion", list); g_free(list); /* layer */ GST_LOG_OBJECT(self, "setting mpeg layer"); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (mpeg->layer & BT_MPEG_LAYER_1) { g_value_set_int(value, 1); gst_value_list_prepend_value(list, value); valid_layer = TRUE; } if (mpeg->layer & BT_MPEG_LAYER_2) { g_value_set_int(value, 2); gst_value_list_prepend_value(list, value); valid_layer = TRUE; } if (mpeg->layer & BT_MPEG_LAYER_3) { g_value_set_int(value, 3); gst_value_list_prepend_value(list, value); valid_layer = TRUE; } if (list) { gst_structure_set_value(structure, "layer", list); g_free(list); list = NULL; } if (!valid_layer) { gst_structure_free(structure); g_free(value); return NULL; } /* rate */ GST_LOG_OBJECT(self, "setting mpeg rate"); list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST); if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_48000) { g_value_set_int(value, 48000); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_44100) { g_value_set_int(value, 44100); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_32000) { g_value_set_int(value, 32000); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_24000) { g_value_set_int(value, 24000); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_22050) { g_value_set_int(value, 22050); gst_value_list_prepend_value(list, value); } if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_16000) { g_value_set_int(value, 16000); gst_value_list_prepend_value(list, value); } g_value_unset(value); if (list) { gst_structure_set_value(structure, "rate", list); g_free(list); list = NULL; } /* channels */ GST_LOG_OBJECT(self, "setting mpeg channels"); mono = FALSE; stereo = FALSE; if (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) mono = TRUE; if ((mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) || (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) || (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)) stereo = TRUE; if (mono && stereo) { g_value_init(value, GST_TYPE_INT_RANGE); gst_value_set_int_range(value, 1, 2); } else { g_value_init(value, G_TYPE_INT); if (mono) g_value_set_int(value, 1); else if (stereo) g_value_set_int(value, 2); else { GST_ERROR_OBJECT(self, "Unexpected number of channels"); g_value_set_int(value, 0); } } gst_structure_set_value(structure, "channels", value); g_free(value); return structure; } static gboolean gst_avdtp_sink_update_config(GstAvdtpSink *self) { GstStructure *structure; gchar *tmp; switch (self->data->codec) { case A2DP_CODEC_SBC: structure = gst_avdtp_sink_parse_sbc_raw(self); break; case A2DP_CODEC_MPEG12: structure = gst_avdtp_sink_parse_mpeg_raw(self); break; default: GST_ERROR_OBJECT(self, "Unsupported configuration"); return FALSE; } if (structure == NULL) return FALSE; if (self->dev_caps != NULL) gst_caps_unref(self->dev_caps); self->dev_caps = gst_caps_new_full(structure, NULL); tmp = gst_caps_to_string(self->dev_caps); GST_DEBUG_OBJECT(self, "Transport configuration: %s", tmp); g_free(tmp); return TRUE; } static gboolean gst_avdtp_sink_update_caps(GstAvdtpSink *self) { sbc_capabilities_t *sbc; mpeg_capabilities_t *mpeg; GstStructure *sbc_structure; GstStructure *mpeg_structure; gchar *tmp; GST_LOG_OBJECT(self, "updating device caps"); if (self->data->config_size != 0 && self->data->config != NULL) return gst_avdtp_sink_update_config(self); sbc = (void *) gst_avdtp_find_caps(self, BT_A2DP_SBC_SINK); mpeg = (void *) gst_avdtp_find_caps(self, BT_A2DP_MPEG12_SINK); if (!sbc) { GST_ERROR_OBJECT(self, "Failed to find mandatory SBC sink"); return FALSE; } sbc_structure = gst_avdtp_sink_parse_sbc_caps(self, sbc); mpeg_structure = gst_avdtp_sink_parse_mpeg_caps(self, mpeg); if (self->dev_caps != NULL) gst_caps_unref(self->dev_caps); self->dev_caps = gst_caps_new_full(sbc_structure, NULL); if (mpeg_structure != NULL) gst_caps_append_structure(self->dev_caps, mpeg_structure); tmp = gst_caps_to_string(self->dev_caps); GST_DEBUG_OBJECT(self, "Device capabilities: %s", tmp); g_free(tmp); return TRUE; } static gboolean gst_avdtp_sink_get_capabilities(GstAvdtpSink *self) { gchar buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_get_capabilities_req *req = (void *) buf; struct bt_get_capabilities_rsp *rsp = (void *) buf; int err; memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); req->h.type = BT_REQUEST; req->h.name = BT_GET_CAPABILITIES; req->h.length = sizeof(*req); if (self->device == NULL) return FALSE; strncpy(req->destination, self->device, 18); if (self->autoconnect) req->flags |= BT_FLAG_AUTOCONNECT; err = gst_avdtp_sink_audioservice_send(self, &req->h); if (err < 0) { GST_ERROR_OBJECT(self, "Error while asking device caps"); return FALSE; } rsp->h.length = 0; err = gst_avdtp_sink_audioservice_expect(self, &rsp->h, BT_GET_CAPABILITIES); if (err < 0) { GST_ERROR_OBJECT(self, "Error while getting device caps"); return FALSE; } self->data->caps = g_malloc0(rsp->h.length); memcpy(self->data->caps, rsp, rsp->h.length); if (!gst_avdtp_sink_update_caps(self)) { GST_WARNING_OBJECT(self, "failed to update capabilities"); return FALSE; } return TRUE; } static gint gst_avdtp_sink_get_channel_mode(const gchar *mode) { if (strcmp(mode, "stereo") == 0) return BT_A2DP_CHANNEL_MODE_STEREO; else if (strcmp(mode, "joint-stereo") == 0) return BT_A2DP_CHANNEL_MODE_JOINT_STEREO; else if (strcmp(mode, "dual-channel") == 0) return BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL; else if (strcmp(mode, "mono") == 0) return BT_A2DP_CHANNEL_MODE_MONO; else return -1; } static void gst_avdtp_sink_tag(const GstTagList *taglist, const gchar *tag, gpointer user_data) { gboolean crc; gchar *channel_mode = NULL; GstAvdtpSink *self = GST_AVDTP_SINK(user_data); if (strcmp(tag, "has-crc") == 0) { if (!gst_tag_list_get_boolean(taglist, tag, &crc)) { GST_WARNING_OBJECT(self, "failed to get crc tag"); return; } gst_avdtp_sink_set_crc(self, crc); } else if (strcmp(tag, "channel-mode") == 0) { if (!gst_tag_list_get_string(taglist, tag, &channel_mode)) { GST_WARNING_OBJECT(self, "failed to get channel-mode tag"); return; } self->channel_mode = gst_avdtp_sink_get_channel_mode( channel_mode); if (self->channel_mode == -1) GST_WARNING_OBJECT(self, "Received invalid channel " "mode: %s", channel_mode); g_free(channel_mode); } else GST_DEBUG_OBJECT(self, "received unused tag: %s", tag); } static gboolean gst_avdtp_sink_event(GstBaseSink *basesink, GstEvent *event) { GstAvdtpSink *self = GST_AVDTP_SINK(basesink); GstTagList *taglist = NULL; if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) { /* we check the tags, mp3 has tags that are importants and * are outside caps */ gst_event_parse_tag(event, &taglist); gst_tag_list_foreach(taglist, gst_avdtp_sink_tag, self); } return TRUE; } static gboolean gst_avdtp_sink_transport_parse_property(GstAvdtpSink *self, DBusMessageIter *i) { const char *key; DBusMessageIter variant_i; if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) { GST_ERROR_OBJECT(self, "Property name not a string."); return FALSE; } dbus_message_iter_get_basic(i, &key); if (!dbus_message_iter_next(i)) { GST_ERROR_OBJECT(self, "Property value missing"); return FALSE; } if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) { GST_ERROR_OBJECT(self, "Property value not a variant."); return FALSE; } dbus_message_iter_recurse(i, &variant_i); switch (dbus_message_iter_get_arg_type(&variant_i)) { case DBUS_TYPE_BYTE: { uint8_t value; dbus_message_iter_get_basic(&variant_i, &value); if (g_str_equal(key, "Codec") == TRUE) self->data->codec = value; break; } case DBUS_TYPE_STRING: { const char *value; dbus_message_iter_get_basic(&variant_i, &value); if (g_str_equal(key, "UUID") == TRUE) { g_free(self->data->uuid); self->data->uuid = g_strdup(value); } break; } case DBUS_TYPE_ARRAY: { DBusMessageIter array_i; char *value; int size; dbus_message_iter_recurse(&variant_i, &array_i); dbus_message_iter_get_fixed_array(&array_i, &value, &size); if (g_str_equal(key, "Configuration")) { g_free(self->data->config); self->data->config = g_new0(guint8, size); self->data->config_size = size; memcpy(self->data->config, value, size); } break; } } return TRUE; } static gboolean gst_avdtp_sink_transport_acquire(GstAvdtpSink *self) { DBusMessage *msg, *reply; DBusError err; const char *access_type = "w"; int fd; uint16_t imtu, omtu; dbus_error_init(&err); if (self->data->conn == NULL) self->data->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err); msg = dbus_message_new_method_call("org.bluez", self->transport, "org.bluez.MediaTransport", "Acquire"); dbus_message_append_args(msg, DBUS_TYPE_STRING, &access_type, DBUS_TYPE_INVALID); reply = dbus_connection_send_with_reply_and_block(self->data->conn, msg, -1, &err); dbus_message_unref(msg); if (dbus_error_is_set(&err)) goto fail; if (dbus_message_get_args(reply, &err, DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_UINT16, &imtu, DBUS_TYPE_UINT16, &omtu, DBUS_TYPE_INVALID) == FALSE) goto fail; dbus_message_unref(reply); self->stream = g_io_channel_unix_new(fd); g_io_channel_set_encoding(self->stream, NULL, NULL); g_io_channel_set_close_on_unref(self->stream, TRUE); self->data->link_mtu = omtu; GST_DEBUG_OBJECT(self, "stream_fd=%d mtu=%d", fd, omtu); return TRUE; fail: GST_ERROR_OBJECT(self, "Failed to acquire transport stream: %s", err.message); dbus_error_free(&err); if (reply) dbus_message_unref(reply); return FALSE; } static gboolean gst_avdtp_sink_transport_get_properties(GstAvdtpSink *self) { DBusMessage *msg, *reply; DBusMessageIter arg_i, ele_i; DBusError err; dbus_error_init(&err); /* Transport need to be acquire first to make sure the MTUs are available */ if (gst_avdtp_sink_transport_acquire(self) == FALSE) return FALSE; msg = dbus_message_new_method_call("org.bluez", self->transport, "org.bluez.MediaTransport", "GetProperties"); reply = dbus_connection_send_with_reply_and_block(self->data->conn, msg, -1, &err); if (dbus_error_is_set(&err) || reply == NULL) { GST_ERROR_OBJECT(self, "Failed to get transport properties: %s", err.message); goto fail; } if (!dbus_message_iter_init(reply, &arg_i)) { GST_ERROR_OBJECT(self, "GetProperties reply has no arguments."); goto fail; } if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) { GST_ERROR_OBJECT(self, "GetProperties argument is not an array."); goto fail; } dbus_message_iter_recurse(&arg_i, &ele_i); while (dbus_message_iter_get_arg_type(&ele_i) != DBUS_TYPE_INVALID) { if (dbus_message_iter_get_arg_type(&ele_i) == DBUS_TYPE_DICT_ENTRY) { DBusMessageIter dict_i; dbus_message_iter_recurse(&ele_i, &dict_i); gst_avdtp_sink_transport_parse_property(self, &dict_i); } if (!dbus_message_iter_next(&ele_i)) break; } return gst_avdtp_sink_update_caps(self); fail: dbus_message_unref(msg); dbus_message_unref(reply); return FALSE; } static gboolean gst_avdtp_sink_start(GstBaseSink *basesink) { GstAvdtpSink *self = GST_AVDTP_SINK(basesink); gint sk; gint err; GST_INFO_OBJECT(self, "start"); self->data = g_new0(struct bluetooth_data, 1); self->stream = NULL; self->stream_caps = NULL; self->mp3_using_crc = -1; self->channel_mode = -1; if (self->transport != NULL) return gst_avdtp_sink_transport_get_properties(self); self->watch_id = 0; sk = bt_audio_service_open(); if (sk < 0) { err = -errno; GST_ERROR_OBJECT(self, "Cannot open connection to bt " "audio service: %s %d", strerror(-err), -err); return FALSE; } self->server = g_io_channel_unix_new(sk); g_io_channel_set_encoding(self->server, NULL, NULL); self->watch_id = g_io_add_watch(self->server, G_IO_HUP | G_IO_ERR | G_IO_NVAL, server_callback, self); if (!gst_avdtp_sink_get_capabilities(self)) { GST_ERROR_OBJECT(self, "failed to get capabilities " "from device"); goto failed; } return TRUE; failed: bt_audio_service_close(sk); return FALSE; } static gboolean gst_avdtp_sink_stream_start(GstAvdtpSink *self) { gchar buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_start_stream_req *req = (void *) buf; struct bt_start_stream_rsp *rsp = (void *) buf; struct bt_new_stream_ind *ind = (void *) buf; int err; if (self->transport != NULL) return gst_avdtp_sink_conf_recv_stream_fd(self); memset(req, 0, sizeof(buf)); req->h.type = BT_REQUEST; req->h.name = BT_START_STREAM; req->h.length = sizeof(*req); err = gst_avdtp_sink_audioservice_send(self, &req->h); if (err < 0) { GST_ERROR_OBJECT(self, "Error occurred while sending " "start packet"); return FALSE; } rsp->h.length = sizeof(*rsp); err = gst_avdtp_sink_audioservice_expect(self, &rsp->h, BT_START_STREAM); if (err < 0) { GST_ERROR_OBJECT(self, "Error while stream " "start confirmation"); return FALSE; } ind->h.length = sizeof(*ind); err = gst_avdtp_sink_audioservice_expect(self, &ind->h, BT_NEW_STREAM); if (err < 0) { GST_ERROR_OBJECT(self, "Error while receiving " "stream filedescriptor"); return FALSE; } if (!gst_avdtp_sink_conf_recv_stream_fd(self)) return FALSE; return TRUE; } static gboolean gst_avdtp_sink_init_mp3_pkt_conf( GstAvdtpSink *self, GstCaps *caps, mpeg_capabilities_t *pkt) { const GValue *value = NULL; gint rate, layer; const gchar *name; GstStructure *structure = gst_caps_get_structure(caps, 0); name = gst_structure_get_name(structure); if (!(IS_MPEG_AUDIO(name))) { GST_ERROR_OBJECT(self, "Unexpected format %s, " "was expecting mp3", name); return FALSE; } /* layer */ value = gst_structure_get_value(structure, "layer"); layer = g_value_get_int(value); if (layer == 1) pkt->layer = BT_MPEG_LAYER_1; else if (layer == 2) pkt->layer = BT_MPEG_LAYER_2; else if (layer == 3) pkt->layer = BT_MPEG_LAYER_3; else { GST_ERROR_OBJECT(self, "Unexpected layer: %d", layer); return FALSE; } /* crc */ if (self->mp3_using_crc != -1) pkt->crc = self->mp3_using_crc; else { GST_ERROR_OBJECT(self, "No info about crc was received, " " can't proceed"); return FALSE; } /* channel mode */ if (self->channel_mode != -1) pkt->channel_mode = self->channel_mode; else { GST_ERROR_OBJECT(self, "No info about channel mode " "received, can't proceed"); return FALSE; } /* mpf - we will only use the mandatory one */ pkt->mpf = 0; value = gst_structure_get_value(structure, "rate"); rate = g_value_get_int(value); if (rate == 44100) pkt->frequency = BT_MPEG_SAMPLING_FREQ_44100; else if (rate == 48000) pkt->frequency = BT_MPEG_SAMPLING_FREQ_48000; else if (rate == 32000) pkt->frequency = BT_MPEG_SAMPLING_FREQ_32000; else if (rate == 24000) pkt->frequency = BT_MPEG_SAMPLING_FREQ_24000; else if (rate == 22050) pkt->frequency = BT_MPEG_SAMPLING_FREQ_22050; else if (rate == 16000) pkt->frequency = BT_MPEG_SAMPLING_FREQ_16000; else { GST_ERROR_OBJECT(self, "Invalid rate while setting caps"); return FALSE; } /* vbr - we always say its vbr, we don't have how to know it */ pkt->bitrate = 0x8000; return TRUE; } static gboolean gst_avdtp_sink_configure(GstAvdtpSink *self, GstCaps *caps) { gchar buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_open_req *open_req = (void *) buf; struct bt_open_rsp *open_rsp = (void *) buf; struct bt_set_configuration_req *req = (void *) buf; struct bt_set_configuration_rsp *rsp = (void *) buf; gboolean ret; gchar *temp; GstStructure *structure; codec_capabilities_t *codec = NULL; int err; temp = gst_caps_to_string(caps); GST_DEBUG_OBJECT(self, "configuring device with caps: %s", temp); g_free(temp); /* Transport already configured */ if (self->transport != NULL) return TRUE; structure = gst_caps_get_structure(caps, 0); if (gst_structure_has_name(structure, "audio/x-sbc")) codec = (void *) gst_avdtp_find_caps(self, BT_A2DP_SBC_SINK); else if (gst_structure_has_name(structure, "audio/mpeg")) codec = (void *) gst_avdtp_find_caps(self, BT_A2DP_MPEG12_SINK); if (codec == NULL) { GST_ERROR_OBJECT(self, "Couldn't parse caps " "to packet configuration"); return FALSE; } memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); open_req->h.type = BT_REQUEST; open_req->h.name = BT_OPEN; open_req->h.length = sizeof(*open_req); strncpy(open_req->destination, self->device, 18); open_req->seid = codec->seid; open_req->lock = BT_WRITE_LOCK; err = gst_avdtp_sink_audioservice_send(self, &open_req->h); if (err < 0) { GST_ERROR_OBJECT(self, "Error occurred while sending " "open packet"); return FALSE; } open_rsp->h.length = sizeof(*open_rsp); err = gst_avdtp_sink_audioservice_expect(self, &open_rsp->h, BT_OPEN); if (err < 0) { GST_ERROR_OBJECT(self, "Error while receiving device " "confirmation"); return FALSE; } memset(req, 0, sizeof(buf)); req->h.type = BT_REQUEST; req->h.name = BT_SET_CONFIGURATION; req->h.length = sizeof(*req); memcpy(&req->codec, codec, sizeof(req->codec)); if (codec->type == BT_A2DP_SBC_SINK) ret = gst_avdtp_sink_init_sbc_pkt_conf(self, caps, (void *) &req->codec); else ret = gst_avdtp_sink_init_mp3_pkt_conf(self, caps, (void *) &req->codec); if (!ret) { GST_ERROR_OBJECT(self, "Couldn't parse caps " "to packet configuration"); return FALSE; } req->h.length += req->codec.length - sizeof(req->codec); err = gst_avdtp_sink_audioservice_send(self, &req->h); if (err < 0) { GST_ERROR_OBJECT(self, "Error occurred while sending " "configurarion packet"); return FALSE; } rsp->h.length = sizeof(*rsp); err = gst_avdtp_sink_audioservice_expect(self, &rsp->h, BT_SET_CONFIGURATION); if (err < 0) { GST_ERROR_OBJECT(self, "Error while receiving device " "confirmation"); return FALSE; } self->data->link_mtu = rsp->link_mtu; return TRUE; } static GstFlowReturn gst_avdtp_sink_preroll(GstBaseSink *basesink, GstBuffer *buffer) { GstAvdtpSink *sink = GST_AVDTP_SINK(basesink); gboolean ret; GST_AVDTP_SINK_MUTEX_LOCK(sink); ret = gst_avdtp_sink_stream_start(sink); GST_AVDTP_SINK_MUTEX_UNLOCK(sink); if (!ret) return GST_FLOW_ERROR; return GST_FLOW_OK; } static GstFlowReturn gst_avdtp_sink_render(GstBaseSink *basesink, GstBuffer *buffer) { GstAvdtpSink *self = GST_AVDTP_SINK(basesink); ssize_t ret; int fd; fd = g_io_channel_unix_get_fd(self->stream); ret = write(fd, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer)); if (ret < 0) { GST_ERROR_OBJECT(self, "Error while writting to socket: %s", strerror(errno)); return GST_FLOW_ERROR; } return GST_FLOW_OK; } static gboolean gst_avdtp_sink_unlock(GstBaseSink *basesink) { GstAvdtpSink *self = GST_AVDTP_SINK(basesink); if (self->stream != NULL) g_io_channel_flush(self->stream, NULL); return TRUE; } static GstFlowReturn gst_avdtp_sink_buffer_alloc(GstBaseSink *basesink, guint64 offset, guint size, GstCaps *caps, GstBuffer **buf) { GstAvdtpSink *self = GST_AVDTP_SINK(basesink); *buf = gst_buffer_new_and_alloc(size); if (!(*buf)) { GST_ERROR_OBJECT(self, "buffer allocation failed"); return GST_FLOW_ERROR; } gst_buffer_set_caps(*buf, caps); GST_BUFFER_OFFSET(*buf) = offset; return GST_FLOW_OK; } static void gst_avdtp_sink_class_init(GstAvdtpSinkClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS(klass); parent_class = g_type_class_peek_parent(klass); object_class->finalize = GST_DEBUG_FUNCPTR( gst_avdtp_sink_finalize); object_class->set_property = GST_DEBUG_FUNCPTR( gst_avdtp_sink_set_property); object_class->get_property = GST_DEBUG_FUNCPTR( gst_avdtp_sink_get_property); basesink_class->start = GST_DEBUG_FUNCPTR(gst_avdtp_sink_start); basesink_class->stop = GST_DEBUG_FUNCPTR(gst_avdtp_sink_stop); basesink_class->render = GST_DEBUG_FUNCPTR( gst_avdtp_sink_render); basesink_class->preroll = GST_DEBUG_FUNCPTR( gst_avdtp_sink_preroll); basesink_class->unlock = GST_DEBUG_FUNCPTR( gst_avdtp_sink_unlock); basesink_class->event = GST_DEBUG_FUNCPTR( gst_avdtp_sink_event); basesink_class->buffer_alloc = GST_DEBUG_FUNCPTR(gst_avdtp_sink_buffer_alloc); g_object_class_install_property(object_class, PROP_DEVICE, g_param_spec_string("device", "Device", "Bluetooth remote device address", NULL, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_AUTOCONNECT, g_param_spec_boolean("auto-connect", "Auto-connect", "Automatically attempt to connect " "to device", DEFAULT_AUTOCONNECT, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_TRANSPORT, g_param_spec_string("transport", "Transport", "Use configured transport", NULL, G_PARAM_READWRITE)); GST_DEBUG_CATEGORY_INIT(avdtp_sink_debug, "avdtpsink", 0, "A2DP headset sink element"); } static void gst_avdtp_sink_init(GstAvdtpSink *self, GstAvdtpSinkClass *klass) { self->device = NULL; self->transport = NULL; self->data = NULL; self->stream = NULL; self->dev_caps = NULL; self->autoconnect = DEFAULT_AUTOCONNECT; self->sink_lock = g_mutex_new(); /* FIXME this is for not synchronizing with clock, should be tested * with devices to see the behaviour gst_base_sink_set_sync(GST_BASE_SINK(self), FALSE); */ } static int gst_avdtp_sink_audioservice_send(GstAvdtpSink *self, const bt_audio_msg_header_t *msg) { ssize_t written; const char *type, *name; uint16_t length; int fd, err; length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE; fd = g_io_channel_unix_get_fd(self->server); written = write(fd, msg, length); if (written < 0) { err = -errno; GST_ERROR_OBJECT(self, "Error sending data to audio service:" " %s", strerror(-err)); return err; } type = bt_audio_strtype(msg->type); name = bt_audio_strname(msg->name); GST_DEBUG_OBJECT(self, "sent: %s -> %s", type, name); return 0; } static int gst_avdtp_sink_audioservice_recv(GstAvdtpSink *self, bt_audio_msg_header_t *inmsg) { ssize_t bytes_read; const char *type, *name; uint16_t length; int fd, err = 0; length = inmsg->length ? inmsg->length : BT_SUGGESTED_BUFFER_SIZE; fd = g_io_channel_unix_get_fd(self->server); bytes_read = read(fd, inmsg, length); if (bytes_read < 0) { err = -errno; GST_ERROR_OBJECT(self, "Error receiving data from " "audio service: %s", strerror(-err)); return err; } type = bt_audio_strtype(inmsg->type); if (!type) { err = -EINVAL; GST_ERROR_OBJECT(self, "Bogus message type %d " "received from audio service", inmsg->type); } name = bt_audio_strname(inmsg->name); if (!name) { err = -EINVAL; GST_ERROR_OBJECT(self, "Bogus message name %d " "received from audio service", inmsg->name); } if (inmsg->type == BT_ERROR) { bt_audio_error_t *msg = (void *) inmsg; err = -EINVAL; GST_ERROR_OBJECT(self, "%s failed : " "%s(%d)", name, strerror(msg->posix_errno), msg->posix_errno); } GST_DEBUG_OBJECT(self, "received: %s <- %s", type, name); return err; } static int gst_avdtp_sink_audioservice_expect(GstAvdtpSink *self, bt_audio_msg_header_t *outmsg, guint8 expected_name) { int err; err = gst_avdtp_sink_audioservice_recv(self, outmsg); if (err < 0) return err; if (outmsg->name != expected_name) return -EINVAL; return 0; } gboolean gst_avdtp_sink_plugin_init(GstPlugin *plugin) { return gst_element_register(plugin, "avdtpsink", GST_RANK_NONE, GST_TYPE_AVDTP_SINK); } /* public functions */ GstCaps *gst_avdtp_sink_get_device_caps(GstAvdtpSink *sink) { if (sink->dev_caps == NULL) return NULL; return gst_caps_copy(sink->dev_caps); } gboolean gst_avdtp_sink_set_device_caps(GstAvdtpSink *self, GstCaps *caps) { gboolean ret; GST_DEBUG_OBJECT(self, "setting device caps"); GST_AVDTP_SINK_MUTEX_LOCK(self); ret = gst_avdtp_sink_configure(self, caps); if (self->stream_caps) gst_caps_unref(self->stream_caps); self->stream_caps = gst_caps_ref(caps); GST_AVDTP_SINK_MUTEX_UNLOCK(self); return ret; } guint gst_avdtp_sink_get_link_mtu(GstAvdtpSink *sink) { return sink->data->link_mtu; } void gst_avdtp_sink_set_device(GstAvdtpSink *self, const gchar *dev) { if (self->device != NULL) g_free(self->device); GST_LOG_OBJECT(self, "Setting device: %s", dev); self->device = g_strdup(dev); } void gst_avdtp_sink_set_transport(GstAvdtpSink *self, const gchar *trans) { if (self->transport != NULL) g_free(self->transport); GST_LOG_OBJECT(self, "Setting transport: %s", trans); self->transport = g_strdup(trans); } gchar *gst_avdtp_sink_get_device(GstAvdtpSink *self) { return g_strdup(self->device); } gchar *gst_avdtp_sink_get_transport(GstAvdtpSink *self) { return g_strdup(self->transport); } void gst_avdtp_sink_set_crc(GstAvdtpSink *self, gboolean crc) { gint new_crc; new_crc = crc ? CRC_PROTECTED : CRC_UNPROTECTED; /* test if we already received a different crc */ if (self->mp3_using_crc != -1 && new_crc != self->mp3_using_crc) { GST_WARNING_OBJECT(self, "crc changed during stream"); return; } self->mp3_using_crc = new_crc; } void gst_avdtp_sink_set_channel_mode(GstAvdtpSink *self, const gchar *mode) { gint new_mode; new_mode = gst_avdtp_sink_get_channel_mode(mode); if (self->channel_mode != -1 && new_mode != self->channel_mode) { GST_WARNING_OBJECT(self, "channel mode changed during stream"); return; } self->channel_mode = new_mode; if (self->channel_mode == -1) GST_WARNING_OBJECT(self, "Received invalid channel " "mode: %s", mode); } bluez-4.101/audio/ipc.h0000644000000000000000000002245711766125764011605 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* Message sequence chart of streaming sequence for A2DP transport Audio daemon User on snd_pcm_open <--BT_GET_CAPABILITIES_REQ BT_GET_CAPABILITIES_RSP--> on snd_pcm_hw_params <--BT_SETCONFIGURATION_REQ BT_SET_CONFIGURATION_RSP--> on snd_pcm_prepare <--BT_START_STREAM_REQ BT_START_STREAM_RSP--> BT_NEW_STREAM_IND --> < streams data > .......... on snd_pcm_drop/snd_pcm_drain <--BT_STOP_STREAM_REQ BT_STOP_STREAM_RSP--> on IPC close or appl crash */ #ifndef BT_AUDIOCLIENT_H #define BT_AUDIOCLIENT_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #define BT_SUGGESTED_BUFFER_SIZE 512 #define BT_IPC_SOCKET_NAME "\0/org/bluez/audio" /* Generic message header definition, except for RESPONSE messages */ typedef struct { uint8_t type; uint8_t name; uint16_t length; } __attribute__ ((packed)) bt_audio_msg_header_t; typedef struct { bt_audio_msg_header_t h; uint8_t posix_errno; } __attribute__ ((packed)) bt_audio_error_t; /* Message types */ #define BT_REQUEST 0 #define BT_RESPONSE 1 #define BT_INDICATION 2 #define BT_ERROR 3 /* Messages names */ #define BT_GET_CAPABILITIES 0 #define BT_OPEN 1 #define BT_SET_CONFIGURATION 2 #define BT_NEW_STREAM 3 #define BT_START_STREAM 4 #define BT_STOP_STREAM 5 #define BT_CLOSE 6 #define BT_CONTROL 7 #define BT_DELAY_REPORT 8 #define BT_CAPABILITIES_TRANSPORT_A2DP 0 #define BT_CAPABILITIES_TRANSPORT_SCO 1 #define BT_CAPABILITIES_TRANSPORT_ANY 2 #define BT_CAPABILITIES_ACCESS_MODE_READ 1 #define BT_CAPABILITIES_ACCESS_MODE_WRITE 2 #define BT_CAPABILITIES_ACCESS_MODE_READWRITE 3 #define BT_FLAG_AUTOCONNECT 1 struct bt_get_capabilities_req { bt_audio_msg_header_t h; char source[18]; /* Address of the local Device */ char destination[18];/* Address of the remote Device */ char object[128]; /* DBus object path */ uint8_t transport; /* Requested transport */ uint8_t flags; /* Requested flags */ uint8_t seid; /* Requested capability configuration */ } __attribute__ ((packed)); /** * SBC Codec parameters as per A2DP profile 1.0 § 4.3 */ /* A2DP seid are 6 bytes long so HSP/HFP are assigned to 7-8 bits */ #define BT_A2DP_SEID_RANGE (1 << 6) - 1 #define BT_A2DP_SBC_SOURCE 0x00 #define BT_A2DP_SBC_SINK 0x01 #define BT_A2DP_MPEG12_SOURCE 0x02 #define BT_A2DP_MPEG12_SINK 0x03 #define BT_A2DP_MPEG24_SOURCE 0x04 #define BT_A2DP_MPEG24_SINK 0x05 #define BT_A2DP_ATRAC_SOURCE 0x06 #define BT_A2DP_ATRAC_SINK 0x07 #define BT_A2DP_UNKNOWN_SOURCE 0x08 #define BT_A2DP_UNKNOWN_SINK 0x09 #define BT_SBC_SAMPLING_FREQ_16000 (1 << 3) #define BT_SBC_SAMPLING_FREQ_32000 (1 << 2) #define BT_SBC_SAMPLING_FREQ_44100 (1 << 1) #define BT_SBC_SAMPLING_FREQ_48000 1 #define BT_A2DP_CHANNEL_MODE_MONO (1 << 3) #define BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL (1 << 2) #define BT_A2DP_CHANNEL_MODE_STEREO (1 << 1) #define BT_A2DP_CHANNEL_MODE_JOINT_STEREO 1 #define BT_A2DP_BLOCK_LENGTH_4 (1 << 3) #define BT_A2DP_BLOCK_LENGTH_8 (1 << 2) #define BT_A2DP_BLOCK_LENGTH_12 (1 << 1) #define BT_A2DP_BLOCK_LENGTH_16 1 #define BT_A2DP_SUBBANDS_4 (1 << 1) #define BT_A2DP_SUBBANDS_8 1 #define BT_A2DP_ALLOCATION_SNR (1 << 1) #define BT_A2DP_ALLOCATION_LOUDNESS 1 #define BT_MPEG_SAMPLING_FREQ_16000 (1 << 5) #define BT_MPEG_SAMPLING_FREQ_22050 (1 << 4) #define BT_MPEG_SAMPLING_FREQ_24000 (1 << 3) #define BT_MPEG_SAMPLING_FREQ_32000 (1 << 2) #define BT_MPEG_SAMPLING_FREQ_44100 (1 << 1) #define BT_MPEG_SAMPLING_FREQ_48000 1 #define BT_MPEG_LAYER_1 (1 << 2) #define BT_MPEG_LAYER_2 (1 << 1) #define BT_MPEG_LAYER_3 1 #define BT_HFP_CODEC_PCM 0x00 #define BT_PCM_FLAG_NREC 0x01 #define BT_PCM_FLAG_PCM_ROUTING 0x02 #define BT_WRITE_LOCK (1 << 1) #define BT_READ_LOCK 1 typedef struct { uint8_t seid; uint8_t transport; uint8_t type; uint8_t length; uint8_t configured; uint8_t lock; uint8_t data[0]; } __attribute__ ((packed)) codec_capabilities_t; typedef struct { codec_capabilities_t capability; uint8_t channel_mode; uint8_t frequency; uint8_t allocation_method; uint8_t subbands; uint8_t block_length; uint8_t min_bitpool; uint8_t max_bitpool; } __attribute__ ((packed)) sbc_capabilities_t; typedef struct { codec_capabilities_t capability; uint8_t channel_mode; uint8_t crc; uint8_t layer; uint8_t frequency; uint8_t mpf; uint16_t bitrate; } __attribute__ ((packed)) mpeg_capabilities_t; typedef struct { codec_capabilities_t capability; uint8_t flags; uint16_t sampling_rate; } __attribute__ ((packed)) pcm_capabilities_t; struct bt_get_capabilities_rsp { bt_audio_msg_header_t h; char source[18]; /* Address of the local Device */ char destination[18];/* Address of the remote Device */ char object[128]; /* DBus object path */ uint8_t data[0]; /* First codec_capabilities_t */ } __attribute__ ((packed)); struct bt_open_req { bt_audio_msg_header_t h; char source[18]; /* Address of the local Device */ char destination[18];/* Address of the remote Device */ char object[128]; /* DBus object path */ uint8_t seid; /* Requested capability configuration to lock */ uint8_t lock; /* Requested lock */ } __attribute__ ((packed)); struct bt_open_rsp { bt_audio_msg_header_t h; char source[18]; /* Address of the local Device */ char destination[18];/* Address of the remote Device */ char object[128]; /* DBus object path */ } __attribute__ ((packed)); struct bt_set_configuration_req { bt_audio_msg_header_t h; codec_capabilities_t codec; /* Requested codec */ } __attribute__ ((packed)); struct bt_set_configuration_rsp { bt_audio_msg_header_t h; uint16_t link_mtu; /* Max length that transport supports */ } __attribute__ ((packed)); #define BT_STREAM_ACCESS_READ 0 #define BT_STREAM_ACCESS_WRITE 1 #define BT_STREAM_ACCESS_READWRITE 2 struct bt_start_stream_req { bt_audio_msg_header_t h; } __attribute__ ((packed)); struct bt_start_stream_rsp { bt_audio_msg_header_t h; } __attribute__ ((packed)); /* This message is followed by one byte of data containing the stream data fd as ancillary data */ struct bt_new_stream_ind { bt_audio_msg_header_t h; } __attribute__ ((packed)); struct bt_stop_stream_req { bt_audio_msg_header_t h; } __attribute__ ((packed)); struct bt_stop_stream_rsp { bt_audio_msg_header_t h; } __attribute__ ((packed)); struct bt_close_req { bt_audio_msg_header_t h; } __attribute__ ((packed)); struct bt_close_rsp { bt_audio_msg_header_t h; } __attribute__ ((packed)); struct bt_suspend_stream_ind { bt_audio_msg_header_t h; } __attribute__ ((packed)); struct bt_resume_stream_ind { bt_audio_msg_header_t h; } __attribute__ ((packed)); #define BT_CONTROL_KEY_POWER 0x40 #define BT_CONTROL_KEY_VOL_UP 0x41 #define BT_CONTROL_KEY_VOL_DOWN 0x42 #define BT_CONTROL_KEY_MUTE 0x43 #define BT_CONTROL_KEY_PLAY 0x44 #define BT_CONTROL_KEY_STOP 0x45 #define BT_CONTROL_KEY_PAUSE 0x46 #define BT_CONTROL_KEY_RECORD 0x47 #define BT_CONTROL_KEY_REWIND 0x48 #define BT_CONTROL_KEY_FAST_FORWARD 0x49 #define BT_CONTROL_KEY_EJECT 0x4A #define BT_CONTROL_KEY_FORWARD 0x4B #define BT_CONTROL_KEY_BACKWARD 0x4C struct bt_control_req { bt_audio_msg_header_t h; uint8_t mode; /* Control Mode */ uint8_t key; /* Control Key */ } __attribute__ ((packed)); struct bt_control_rsp { bt_audio_msg_header_t h; uint8_t mode; /* Control Mode */ uint8_t key; /* Control Key */ } __attribute__ ((packed)); struct bt_control_ind { bt_audio_msg_header_t h; uint8_t mode; /* Control Mode */ uint8_t key; /* Control Key */ } __attribute__ ((packed)); struct bt_delay_report_req { bt_audio_msg_header_t h; uint16_t delay; } __attribute__ ((packed)); struct bt_delay_report_ind { bt_audio_msg_header_t h; uint16_t delay; } __attribute__ ((packed)); /* Function declaration */ /* Opens a connection to the audio service: return a socket descriptor */ int bt_audio_service_open(void); /* Closes a connection to the audio service */ int bt_audio_service_close(int sk); /* Receives stream data file descriptor : must be called after a BT_STREAMFD_IND message is returned */ int bt_audio_service_get_data_fd(int sk); /* Human readable message type string */ const char *bt_audio_strtype(uint8_t type); /* Human readable message name string */ const char *bt_audio_strname(uint8_t name); #ifdef __cplusplus } #endif #endif /* BT_AUDIOCLIENT_H */ bluez-4.101/audio/transport.h0000644000000000000000000000313711766125764013060 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2007 Nokia Corporation * Copyright (C) 2004-2009 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ struct media_transport; struct media_transport *media_transport_create(DBusConnection *conn, struct media_endpoint *endpoint, struct audio_device *device, uint8_t *configuration, size_t size); void media_transport_destroy(struct media_transport *transport); const char *media_transport_get_path(struct media_transport *transport); struct audio_device *media_transport_get_dev(struct media_transport *transport); void media_transport_update_delay(struct media_transport *transport, uint16_t delay); void media_transport_update_volume(struct media_transport *transport, uint8_t volume); void transport_get_properties(struct media_transport *transport, DBusMessageIter *iter); bluez-4.101/audio/gstsbcparse.h0000644000000000000000000000347311571052274013334 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include "sbc.h" G_BEGIN_DECLS #define GST_TYPE_SBC_PARSE \ (gst_sbc_parse_get_type()) #define GST_SBC_PARSE(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_PARSE,GstSbcParse)) #define GST_SBC_PARSE_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_PARSE,GstSbcParseClass)) #define GST_IS_SBC_PARSE(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_PARSE)) #define GST_IS_SBC_PARSE_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_PARSE)) typedef struct _GstSbcParse GstSbcParse; typedef struct _GstSbcParseClass GstSbcParseClass; struct _GstSbcParse { GstElement element; GstPad *sinkpad; GstPad *srcpad; GstBuffer *buffer; sbc_t sbc; sbc_t new_sbc; GstCaps *outcaps; gboolean first_parsing; gint channels; gint rate; }; struct _GstSbcParseClass { GstElementClass parent_class; }; GType gst_sbc_parse_get_type(void); gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin); G_END_DECLS bluez-4.101/audio/gstsbcutil.c0000644000000000000000000003141011766125764013175 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "gstsbcutil.h" /* * Selects one rate from a list of possible rates * TODO - use a better approach to this (it is selecting the last element) */ gint gst_sbc_select_rate_from_list(const GValue *value) { guint size = gst_value_list_get_size(value); return g_value_get_int(gst_value_list_get_value(value, size-1)); } /* * Selects one number of channels option from a range of possible numbers * TODO - use a better approach to this (it is selecting the maximum value) */ gint gst_sbc_select_channels_from_range(const GValue *value) { return gst_value_get_int_range_max(value); } /* * Selects one number of blocks from a list of possible blocks * TODO - use a better approach to this (it is selecting the last element) */ gint gst_sbc_select_blocks_from_list(const GValue *value) { guint size = gst_value_list_get_size(value); return g_value_get_int(gst_value_list_get_value(value, size-1)); } /* * Selects one number of subbands from a list * TODO - use a better approach to this (it is selecting the last element) */ gint gst_sbc_select_subbands_from_list(const GValue *value) { guint size = gst_value_list_get_size(value); return g_value_get_int(gst_value_list_get_value(value, size-1)); } /* * Selects one bitpool option from a range * TODO - use a better approach to this (it is selecting the maximum value) */ gint gst_sbc_select_bitpool_from_range(const GValue *value) { return gst_value_get_int_range_max(value); } /* * Selects one allocation mode from the ones on the list * TODO - use a better approach */ const gchar *gst_sbc_get_allocation_from_list(const GValue *value) { guint size = gst_value_list_get_size(value); return g_value_get_string(gst_value_list_get_value(value, size-1)); } /* * Selects one mode from the ones on the list */ const gchar *gst_sbc_get_mode_from_list(const GValue *list, gint channels) { unsigned int i; const GValue *value; const gchar *aux; gboolean joint, stereo, dual, mono; guint size = gst_value_list_get_size(list); joint = stereo = dual = mono = FALSE; for (i = 0; i < size; i++) { value = gst_value_list_get_value(list, i); aux = g_value_get_string(value); if (strcmp("joint", aux) == 0) joint = TRUE; else if (strcmp("stereo", aux) == 0) stereo = TRUE; else if (strcmp("dual", aux) == 0) dual = TRUE; else if (strcmp("mono", aux) == 0) mono = TRUE; } if (channels == 1 && mono) return "mono"; else if (channels == 2) { if (joint) return "joint"; else if (stereo) return "stereo"; else if (dual) return "dual"; } return NULL; } gint gst_sbc_parse_rate_from_sbc(gint frequency) { switch (frequency) { case SBC_FREQ_16000: return 16000; case SBC_FREQ_32000: return 32000; case SBC_FREQ_44100: return 44100; case SBC_FREQ_48000: return 48000; default: return 0; } } gint gst_sbc_parse_rate_to_sbc(gint rate) { switch (rate) { case 16000: return SBC_FREQ_16000; case 32000: return SBC_FREQ_32000; case 44100: return SBC_FREQ_44100; case 48000: return SBC_FREQ_48000; default: return -1; } } gint gst_sbc_get_channel_number(gint mode) { switch (mode) { case SBC_MODE_JOINT_STEREO: case SBC_MODE_STEREO: case SBC_MODE_DUAL_CHANNEL: return 2; case SBC_MODE_MONO: return 1; default: return 0; } } gint gst_sbc_parse_subbands_from_sbc(gint subbands) { switch (subbands) { case SBC_SB_4: return 4; case SBC_SB_8: return 8; default: return 0; } } gint gst_sbc_parse_subbands_to_sbc(gint subbands) { switch (subbands) { case 4: return SBC_SB_4; case 8: return SBC_SB_8; default: return -1; } } gint gst_sbc_parse_blocks_from_sbc(gint blocks) { switch (blocks) { case SBC_BLK_4: return 4; case SBC_BLK_8: return 8; case SBC_BLK_12: return 12; case SBC_BLK_16: return 16; default: return 0; } } gint gst_sbc_parse_blocks_to_sbc(gint blocks) { switch (blocks) { case 4: return SBC_BLK_4; case 8: return SBC_BLK_8; case 12: return SBC_BLK_12; case 16: return SBC_BLK_16; default: return -1; } } const gchar *gst_sbc_parse_mode_from_sbc(gint mode) { switch (mode) { case SBC_MODE_MONO: return "mono"; case SBC_MODE_DUAL_CHANNEL: return "dual"; case SBC_MODE_STEREO: return "stereo"; case SBC_MODE_JOINT_STEREO: case SBC_MODE_AUTO: return "joint"; default: return NULL; } } gint gst_sbc_parse_mode_to_sbc(const gchar *mode) { if (g_ascii_strcasecmp(mode, "joint") == 0) return SBC_MODE_JOINT_STEREO; else if (g_ascii_strcasecmp(mode, "stereo") == 0) return SBC_MODE_STEREO; else if (g_ascii_strcasecmp(mode, "dual") == 0) return SBC_MODE_DUAL_CHANNEL; else if (g_ascii_strcasecmp(mode, "mono") == 0) return SBC_MODE_MONO; else if (g_ascii_strcasecmp(mode, "auto") == 0) return SBC_MODE_JOINT_STEREO; else return -1; } const gchar *gst_sbc_parse_allocation_from_sbc(gint alloc) { switch (alloc) { case SBC_AM_LOUDNESS: return "loudness"; case SBC_AM_SNR: return "snr"; case SBC_AM_AUTO: return "loudness"; default: return NULL; } } gint gst_sbc_parse_allocation_to_sbc(const gchar *allocation) { if (g_ascii_strcasecmp(allocation, "loudness") == 0) return SBC_AM_LOUDNESS; else if (g_ascii_strcasecmp(allocation, "snr") == 0) return SBC_AM_SNR; else return SBC_AM_LOUDNESS; } GstCaps *gst_sbc_parse_caps_from_sbc(sbc_t *sbc) { GstCaps *caps; const gchar *mode_str; const gchar *allocation_str; mode_str = gst_sbc_parse_mode_from_sbc(sbc->mode); allocation_str = gst_sbc_parse_allocation_from_sbc(sbc->allocation); caps = gst_caps_new_simple("audio/x-sbc", "rate", G_TYPE_INT, gst_sbc_parse_rate_from_sbc(sbc->frequency), "channels", G_TYPE_INT, gst_sbc_get_channel_number(sbc->mode), "mode", G_TYPE_STRING, mode_str, "subbands", G_TYPE_INT, gst_sbc_parse_subbands_from_sbc(sbc->subbands), "blocks", G_TYPE_INT, gst_sbc_parse_blocks_from_sbc(sbc->blocks), "allocation", G_TYPE_STRING, allocation_str, "bitpool", G_TYPE_INT, sbc->bitpool, NULL); return caps; } /* * Given a GstCaps, this will return a fixed GstCaps on successful conversion. * If an error occurs, it will return NULL and error_message will contain the * error message. * * error_message must be passed NULL, if an error occurs, the caller has the * ownership of the error_message, it must be freed after use. */ GstCaps *gst_sbc_util_caps_fixate(GstCaps *caps, gchar **error_message) { GstCaps *result; GstStructure *structure; const GValue *value; gboolean error = FALSE; gint temp, rate, channels, blocks, subbands, bitpool; const gchar *allocation = NULL; const gchar *mode = NULL; g_assert(*error_message == NULL); structure = gst_caps_get_structure(caps, 0); if (!gst_structure_has_field(structure, "rate")) { error = TRUE; *error_message = g_strdup("no rate"); goto error; } else { value = gst_structure_get_value(structure, "rate"); if (GST_VALUE_HOLDS_LIST(value)) temp = gst_sbc_select_rate_from_list(value); else temp = g_value_get_int(value); rate = temp; } if (!gst_structure_has_field(structure, "channels")) { error = TRUE; *error_message = g_strdup("no channels"); goto error; } else { value = gst_structure_get_value(structure, "channels"); if (GST_VALUE_HOLDS_INT_RANGE(value)) temp = gst_sbc_select_channels_from_range(value); else temp = g_value_get_int(value); channels = temp; } if (!gst_structure_has_field(structure, "blocks")) { error = TRUE; *error_message = g_strdup("no blocks."); goto error; } else { value = gst_structure_get_value(structure, "blocks"); if (GST_VALUE_HOLDS_LIST(value)) temp = gst_sbc_select_blocks_from_list(value); else temp = g_value_get_int(value); blocks = temp; } if (!gst_structure_has_field(structure, "subbands")) { error = TRUE; *error_message = g_strdup("no subbands"); goto error; } else { value = gst_structure_get_value(structure, "subbands"); if (GST_VALUE_HOLDS_LIST(value)) temp = gst_sbc_select_subbands_from_list(value); else temp = g_value_get_int(value); subbands = temp; } if (!gst_structure_has_field(structure, "bitpool")) { error = TRUE; *error_message = g_strdup("no bitpool"); goto error; } else { value = gst_structure_get_value(structure, "bitpool"); if (GST_VALUE_HOLDS_INT_RANGE(value)) temp = gst_sbc_select_bitpool_from_range(value); else temp = g_value_get_int(value); bitpool = temp; } if (!gst_structure_has_field(structure, "allocation")) { error = TRUE; *error_message = g_strdup("no allocation"); goto error; } else { value = gst_structure_get_value(structure, "allocation"); if (GST_VALUE_HOLDS_LIST(value)) allocation = gst_sbc_get_allocation_from_list(value); else allocation = g_value_get_string(value); } if (!gst_structure_has_field(structure, "mode")) { error = TRUE; *error_message = g_strdup("no mode"); goto error; } else { value = gst_structure_get_value(structure, "mode"); if (GST_VALUE_HOLDS_LIST(value)) { mode = gst_sbc_get_mode_from_list(value, channels); } else mode = g_value_get_string(value); } /* perform validation * if channels is 1, we must have channel mode = mono * if channels is 2, we can't have channel mode = mono */ if ( (channels == 1 && (strcmp(mode, "mono") != 0) ) || ( channels == 2 && ( strcmp(mode, "mono") == 0))) { *error_message = g_strdup_printf("Invalid combination of " "channels (%d) and channel mode (%s)", channels, mode); error = TRUE; } error: if (error) return NULL; result = gst_caps_new_simple("audio/x-sbc", "rate", G_TYPE_INT, rate, "channels", G_TYPE_INT, channels, "mode", G_TYPE_STRING, mode, "blocks", G_TYPE_INT, blocks, "subbands", G_TYPE_INT, subbands, "allocation", G_TYPE_STRING, allocation, "bitpool", G_TYPE_INT, bitpool, NULL); return result; } /** * Sets the int field_value to the param "field" on the structure. * value is used to do the operation, it must be a uninitialized (zero-filled) * GValue, it will be left unitialized at the end of the function. */ void gst_sbc_util_set_structure_int_param(GstStructure *structure, const gchar *field, gint field_value, GValue *value) { value = g_value_init(value, G_TYPE_INT); g_value_set_int(value, field_value); gst_structure_set_value(structure, field, value); g_value_unset(value); } /** * Sets the string field_value to the param "field" on the structure. * value is used to do the operation, it must be a uninitialized (zero-filled) * GValue, it will be left unitialized at the end of the function. */ void gst_sbc_util_set_structure_string_param(GstStructure *structure, const gchar *field, const gchar *field_value, GValue *value) { value = g_value_init(value, G_TYPE_STRING); g_value_set_string(value, field_value); gst_structure_set_value(structure, field, value); g_value_unset(value); } gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps) { GstStructure *structure; gint rate, channels, subbands, blocks, bitpool; const gchar *mode; const gchar *allocation; g_assert(gst_caps_is_fixed(caps)); structure = gst_caps_get_structure(caps, 0); if (!gst_structure_get_int(structure, "rate", &rate)) return FALSE; if (!gst_structure_get_int(structure, "channels", &channels)) return FALSE; if (!gst_structure_get_int(structure, "subbands", &subbands)) return FALSE; if (!gst_structure_get_int(structure, "blocks", &blocks)) return FALSE; if (!gst_structure_get_int(structure, "bitpool", &bitpool)) return FALSE; if (!(mode = gst_structure_get_string(structure, "mode"))) return FALSE; if (!(allocation = gst_structure_get_string(structure, "allocation"))) return FALSE; if (channels == 1 && strcmp(mode, "mono") != 0) return FALSE; sbc->frequency = gst_sbc_parse_rate_to_sbc(rate); sbc->blocks = gst_sbc_parse_blocks_to_sbc(blocks); sbc->subbands = gst_sbc_parse_subbands_to_sbc(subbands); sbc->bitpool = bitpool; sbc->mode = gst_sbc_parse_mode_to_sbc(mode); sbc->allocation = gst_sbc_parse_allocation_to_sbc(allocation); return TRUE; } bluez-4.101/audio/audio.conf0000644000000000000000000000272011766125764012620 00000000000000# Configuration file for the audio service # This section contains options which are not specific to any # particular interface [General] # Switch to master role for incoming connections (defaults to true) #Master=true # If we want to disable support for specific services # Defaults to supporting all implemented services #Disable=Gateway,Source,Socket # SCO routing. Either PCM or HCI (in which case audio is routed to/from ALSA) # Defaults to HCI #SCORouting=PCM # Automatically connect both A2DP and HFP/HSP profiles for incoming # connections. Some headsets that support both profiles will only connect the # other one automatically so the default setting of true is usually a good # idea. #AutoConnect=true # Headset interface specific options (i.e. options which affect how the audio # service interacts with remote headset devices) [Headset] # Set to true to support HFP, false means only HSP is supported # Defaults to true HFP=true # Maximum number of connected HSP/HFP devices per adapter. Defaults to 1 MaxConnected=1 # Set to true to enable use of fast connectable mode (faster page scanning) # for HFP when incoming call starts. Default settings are restored after # call is answered or rejected. Page scan interval is much shorter and page # scan type changed to interlaced. Such allows faster connection initiated # by a headset. FastConnectable=false # Just an example of potential config options for the other interfaces #[A2DP] #SBCSources=1 #MPEG12Sources=0 bluez-4.101/audio/device.c0000644000000000000000000005065611766125764012266 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "../src/adapter.h" #include "../src/device.h" #include "error.h" #include "ipc.h" #include "dbus-common.h" #include "device.h" #include "unix.h" #include "avdtp.h" #include "control.h" #include "avctp.h" #include "avrcp.h" #include "headset.h" #include "gateway.h" #include "sink.h" #include "source.h" #define AUDIO_INTERFACE "org.bluez.Audio" #define CONTROL_CONNECT_TIMEOUT 2 #define AVDTP_CONNECT_TIMEOUT 1 #define AVDTP_CONNECT_TIMEOUT_BOOST 1 #define HEADSET_CONNECT_TIMEOUT 1 typedef enum { AUDIO_STATE_DISCONNECTED, AUDIO_STATE_CONNECTING, AUDIO_STATE_CONNECTED, } audio_state_t; struct service_auth { service_auth_cb cb; void *user_data; }; struct dev_priv { audio_state_t state; headset_state_t hs_state; sink_state_t sink_state; avctp_state_t avctp_state; GSList *auths; DBusMessage *conn_req; DBusMessage *dc_req; guint control_timer; guint avdtp_timer; guint headset_timer; guint dc_id; gboolean disconnecting; gboolean authorized; guint auth_idle_id; }; static unsigned int sink_callback_id = 0; static unsigned int avctp_callback_id = 0; static unsigned int avdtp_callback_id = 0; static unsigned int headset_callback_id = 0; static void device_free(struct audio_device *dev) { struct dev_priv *priv = dev->priv; if (dev->conn) dbus_connection_unref(dev->conn); btd_device_unref(dev->btd_dev); if (priv) { if (priv->auths) audio_device_cancel_authorization(dev, NULL, NULL); if (priv->control_timer) g_source_remove(priv->control_timer); if (priv->avdtp_timer) g_source_remove(priv->avdtp_timer); if (priv->headset_timer) g_source_remove(priv->headset_timer); if (priv->dc_req) dbus_message_unref(priv->dc_req); if (priv->conn_req) dbus_message_unref(priv->conn_req); if (priv->dc_id) device_remove_disconnect_watch(dev->btd_dev, priv->dc_id); g_free(priv); } g_free(dev->path); g_free(dev); } static const char *state2str(audio_state_t state) { switch (state) { case AUDIO_STATE_DISCONNECTED: return "disconnected"; case AUDIO_STATE_CONNECTING: return "connecting"; case AUDIO_STATE_CONNECTED: return "connected"; default: error("Invalid audio state %d", state); return NULL; } } static gboolean control_connect_timeout(gpointer user_data) { struct audio_device *dev = user_data; dev->priv->control_timer = 0; if (dev->control) avrcp_connect(dev); return FALSE; } static gboolean device_set_control_timer(struct audio_device *dev) { struct dev_priv *priv = dev->priv; if (!dev->control) return FALSE; if (priv->control_timer) return FALSE; priv->control_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT, control_connect_timeout, dev); return TRUE; } static void device_remove_control_timer(struct audio_device *dev) { if (dev->priv->control_timer) g_source_remove(dev->priv->control_timer); dev->priv->control_timer = 0; } static void device_remove_avdtp_timer(struct audio_device *dev) { if (dev->priv->avdtp_timer) g_source_remove(dev->priv->avdtp_timer); dev->priv->avdtp_timer = 0; } static void device_remove_headset_timer(struct audio_device *dev) { if (dev->priv->headset_timer) g_source_remove(dev->priv->headset_timer); dev->priv->headset_timer = 0; } static void disconnect_cb(struct btd_device *btd_dev, gboolean removal, void *user_data) { struct audio_device *dev = user_data; struct dev_priv *priv = dev->priv; if (priv->state == AUDIO_STATE_DISCONNECTED) return; if (priv->disconnecting) return; priv->disconnecting = TRUE; device_remove_control_timer(dev); device_remove_avdtp_timer(dev); device_remove_headset_timer(dev); if (dev->control) avrcp_disconnect(dev); if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED) sink_shutdown(dev->sink); else if (priv->hs_state != HEADSET_STATE_DISCONNECTED) headset_shutdown(dev); else priv->disconnecting = FALSE; } static void device_set_state(struct audio_device *dev, audio_state_t new_state) { struct dev_priv *priv = dev->priv; const char *state_str; DBusMessage *reply = NULL; state_str = state2str(new_state); if (!state_str) return; if (new_state == AUDIO_STATE_DISCONNECTED) { priv->authorized = FALSE; if (priv->dc_id) { device_remove_disconnect_watch(dev->btd_dev, priv->dc_id); priv->dc_id = 0; } } else if (new_state == AUDIO_STATE_CONNECTING) priv->dc_id = device_add_disconnect_watch(dev->btd_dev, disconnect_cb, dev, NULL); if (dev->priv->state == new_state) { DBG("state change attempted from %s to %s", state_str, state_str); return; } dev->priv->state = new_state; if (new_state == AUDIO_STATE_DISCONNECTED) { if (priv->dc_req) { reply = dbus_message_new_method_return(priv->dc_req); dbus_message_unref(priv->dc_req); priv->dc_req = NULL; g_dbus_send_message(dev->conn, reply); } priv->disconnecting = FALSE; } if (priv->conn_req && new_state != AUDIO_STATE_CONNECTING) { if (new_state == AUDIO_STATE_CONNECTED) reply = dbus_message_new_method_return(priv->conn_req); else reply = btd_error_failed(priv->conn_req, "Connect Failed"); dbus_message_unref(priv->conn_req); priv->conn_req = NULL; g_dbus_send_message(dev->conn, reply); } emit_property_changed(dev->conn, dev->path, AUDIO_INTERFACE, "State", DBUS_TYPE_STRING, &state_str); } static gboolean avdtp_connect_timeout(gpointer user_data) { struct audio_device *dev = user_data; dev->priv->avdtp_timer = 0; if (dev->sink) { struct avdtp *session = avdtp_get(&dev->src, &dev->dst); if (!session) return FALSE; sink_setup_stream(dev->sink, session); avdtp_unref(session); } return FALSE; } static gboolean device_set_avdtp_timer(struct audio_device *dev) { struct dev_priv *priv = dev->priv; guint timeout = AVDTP_CONNECT_TIMEOUT; if (!dev->sink) return FALSE; if (priv->avdtp_timer) return FALSE; /* If the headset is the HSP/HFP RFCOMM initiator, give the headset * time to initiate AVDTP signalling (and avoid further racing) */ if (dev->headset && headset_get_rfcomm_initiator(dev)) timeout += AVDTP_CONNECT_TIMEOUT_BOOST; priv->avdtp_timer = g_timeout_add_seconds(timeout, avdtp_connect_timeout, dev); return TRUE; } static gboolean headset_connect_timeout(gpointer user_data) { struct audio_device *dev = user_data; struct dev_priv *priv = dev->priv; dev->priv->headset_timer = 0; if (dev->headset == NULL) return FALSE; if (headset_config_stream(dev, FALSE, NULL, NULL) == 0) { if (priv->state != AUDIO_STATE_CONNECTED && (priv->sink_state == SINK_STATE_CONNECTED || priv->sink_state == SINK_STATE_PLAYING)) device_set_state(dev, AUDIO_STATE_CONNECTED); } return FALSE; } static gboolean device_set_headset_timer(struct audio_device *dev) { struct dev_priv *priv = dev->priv; if (!dev->headset) return FALSE; if (priv->headset_timer) return FALSE; priv->headset_timer = g_timeout_add_seconds(HEADSET_CONNECT_TIMEOUT, headset_connect_timeout, dev); return TRUE; } static void device_avdtp_cb(struct audio_device *dev, struct avdtp *session, avdtp_session_state_t old_state, avdtp_session_state_t new_state, void *user_data) { if (!dev->sink || !dev->control) return; if (new_state == AVDTP_SESSION_STATE_CONNECTED) { if (avdtp_stream_setup_active(session)) device_set_control_timer(dev); else avrcp_connect(dev); } } static void device_sink_cb(struct audio_device *dev, sink_state_t old_state, sink_state_t new_state, void *user_data) { struct dev_priv *priv = dev->priv; if (!dev->sink) return; priv->sink_state = new_state; switch (new_state) { case SINK_STATE_DISCONNECTED: if (dev->control) { device_remove_control_timer(dev); avrcp_disconnect(dev); } if (priv->hs_state != HEADSET_STATE_DISCONNECTED && (priv->dc_req || priv->disconnecting)) { headset_shutdown(dev); break; } if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_DISCONNECTED); else if (old_state == SINK_STATE_CONNECTING) { switch (priv->hs_state) { case HEADSET_STATE_CONNECTED: case HEADSET_STATE_PLAY_IN_PROGRESS: case HEADSET_STATE_PLAYING: device_set_state(dev, AUDIO_STATE_CONNECTED); default: break; } } break; case SINK_STATE_CONNECTING: device_remove_avdtp_timer(dev); if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_CONNECTING); break; case SINK_STATE_CONNECTED: if (old_state == SINK_STATE_PLAYING) break; if (dev->auto_connect) { if (!dev->headset) device_set_state(dev, AUDIO_STATE_CONNECTED); else if (priv->hs_state == HEADSET_STATE_DISCONNECTED) device_set_headset_timer(dev); else if (priv->hs_state == HEADSET_STATE_CONNECTED || priv->hs_state == HEADSET_STATE_PLAY_IN_PROGRESS || priv->hs_state == HEADSET_STATE_PLAYING) device_set_state(dev, AUDIO_STATE_CONNECTED); } else if (priv->hs_state == HEADSET_STATE_DISCONNECTED || priv->hs_state == HEADSET_STATE_CONNECTING) device_set_state(dev, AUDIO_STATE_CONNECTED); break; case SINK_STATE_PLAYING: break; } } static void device_avctp_cb(struct audio_device *dev, avctp_state_t old_state, avctp_state_t new_state, void *user_data) { if (!dev->control) return; dev->priv->avctp_state = new_state; switch (new_state) { case AVCTP_STATE_DISCONNECTED: break; case AVCTP_STATE_CONNECTING: device_remove_control_timer(dev); break; case AVCTP_STATE_CONNECTED: break; } } static void device_headset_cb(struct audio_device *dev, headset_state_t old_state, headset_state_t new_state, void *user_data) { struct dev_priv *priv = dev->priv; if (!dev->headset) return; priv->hs_state = new_state; switch (new_state) { case HEADSET_STATE_DISCONNECTED: device_remove_avdtp_timer(dev); if (priv->sink_state != SINK_STATE_DISCONNECTED && dev->sink && (priv->dc_req || priv->disconnecting)) { sink_shutdown(dev->sink); break; } if (priv->sink_state == SINK_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_DISCONNECTED); else if (old_state == HEADSET_STATE_CONNECTING && (priv->sink_state == SINK_STATE_CONNECTED || priv->sink_state == SINK_STATE_PLAYING)) device_set_state(dev, AUDIO_STATE_CONNECTED); break; case HEADSET_STATE_CONNECTING: device_remove_headset_timer(dev); if (priv->sink_state == SINK_STATE_DISCONNECTED) device_set_state(dev, AUDIO_STATE_CONNECTING); break; case HEADSET_STATE_CONNECTED: if (old_state == HEADSET_STATE_CONNECTED || old_state == HEADSET_STATE_PLAY_IN_PROGRESS || old_state == HEADSET_STATE_PLAYING) break; if (dev->auto_connect) { if (!dev->sink) device_set_state(dev, AUDIO_STATE_CONNECTED); else if (priv->sink_state == SINK_STATE_DISCONNECTED) device_set_avdtp_timer(dev); else if (priv->sink_state == SINK_STATE_CONNECTED || priv->sink_state == SINK_STATE_PLAYING) device_set_state(dev, AUDIO_STATE_CONNECTED); } else if (priv->sink_state == SINK_STATE_DISCONNECTED || priv->sink_state == SINK_STATE_CONNECTING) device_set_state(dev, AUDIO_STATE_CONNECTED); break; case HEADSET_STATE_PLAY_IN_PROGRESS: break; case HEADSET_STATE_PLAYING: break; } } static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct dev_priv *priv = dev->priv; if (priv->state == AUDIO_STATE_CONNECTING) return btd_error_in_progress(msg); else if (priv->state == AUDIO_STATE_CONNECTED) return btd_error_already_connected(msg); dev->auto_connect = TRUE; if (dev->headset) headset_config_stream(dev, FALSE, NULL, NULL); if (priv->state != AUDIO_STATE_CONNECTING && dev->sink) { struct avdtp *session = avdtp_get(&dev->src, &dev->dst); if (!session) return btd_error_failed(msg, "Failed to get AVDTP session"); sink_setup_stream(dev->sink, session); avdtp_unref(session); } /* The previous calls should cause a call to the state callback to * indicate AUDIO_STATE_CONNECTING */ if (priv->state != AUDIO_STATE_CONNECTING) return btd_error_failed(msg, "Connect Failed"); priv->conn_req = dbus_message_ref(msg); return NULL; } static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct dev_priv *priv = dev->priv; if (priv->state == AUDIO_STATE_DISCONNECTED) return btd_error_not_connected(msg); if (priv->dc_req) return dbus_message_new_method_return(msg); priv->dc_req = dbus_message_ref(msg); if (dev->control) { device_remove_control_timer(dev); avrcp_disconnect(dev); } if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED) sink_shutdown(dev->sink); else if (priv->hs_state != HEADSET_STATE_DISCONNECTED) headset_shutdown(dev); else { dbus_message_unref(priv->dc_req); priv->dc_req = NULL; return dbus_message_new_method_return(msg); } return NULL; } static DBusMessage *dev_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; const char *state; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* State */ state = state2str(device->priv->state); if (state) dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state); dbus_message_iter_close_container(&iter, &dict); return reply; } static const GDBusMethodTable dev_methods[] = { { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dev_connect) }, { GDBUS_METHOD("Disconnect", NULL, NULL, dev_disconnect) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), dev_get_properties) }, { } }; static const GDBusSignalTable dev_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; struct audio_device *audio_device_register(DBusConnection *conn, struct btd_device *device, const char *path, const bdaddr_t *src, const bdaddr_t *dst) { struct audio_device *dev; if (!conn || !path) return NULL; dev = g_new0(struct audio_device, 1); dev->btd_dev = btd_device_ref(device); dev->path = g_strdup(path); bacpy(&dev->dst, dst); bacpy(&dev->src, src); dev->conn = dbus_connection_ref(conn); dev->priv = g_new0(struct dev_priv, 1); dev->priv->state = AUDIO_STATE_DISCONNECTED; if (!g_dbus_register_interface(dev->conn, dev->path, AUDIO_INTERFACE, dev_methods, dev_signals, NULL, dev, NULL)) { error("Unable to register %s on %s", AUDIO_INTERFACE, dev->path); device_free(dev); return NULL; } DBG("Registered interface %s on path %s", AUDIO_INTERFACE, dev->path); if (sink_callback_id == 0) sink_callback_id = sink_add_state_cb(device_sink_cb, NULL); if (avdtp_callback_id == 0) avdtp_callback_id = avdtp_add_state_cb(device_avdtp_cb, NULL); if (avctp_callback_id == 0) avctp_callback_id = avctp_add_state_cb(device_avctp_cb, NULL); if (headset_callback_id == 0) headset_callback_id = headset_add_state_cb(device_headset_cb, NULL); return dev; } gboolean audio_device_is_active(struct audio_device *dev, const char *interface) { if (!interface) { if ((dev->sink || dev->source) && avdtp_is_connected(&dev->src, &dev->dst)) return TRUE; if (dev->headset && headset_is_active(dev)) return TRUE; } else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink && avdtp_is_connected(&dev->src, &dev->dst)) return TRUE; else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source && avdtp_is_connected(&dev->src, &dev->dst)) return TRUE; else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset && headset_is_active(dev)) return TRUE; else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->control && control_is_active(dev)) return TRUE; else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway && gateway_is_active(dev)) return TRUE; return FALSE; } void audio_device_unregister(struct audio_device *device) { unix_device_removed(device); if (device->hs_preauth_id) { g_source_remove(device->hs_preauth_id); device->hs_preauth_id = 0; } if (device->headset) headset_unregister(device); if (device->gateway) gateway_unregister(device); if (device->sink) sink_unregister(device); if (device->source) source_unregister(device); if (device->control) control_unregister(device); g_dbus_unregister_interface(device->conn, device->path, AUDIO_INTERFACE); device_free(device); } static void auth_cb(DBusError *derr, void *user_data) { struct audio_device *dev = user_data; struct dev_priv *priv = dev->priv; if (derr == NULL) priv->authorized = TRUE; while (priv->auths) { struct service_auth *auth = priv->auths->data; auth->cb(derr, auth->user_data); priv->auths = g_slist_remove(priv->auths, auth); g_free(auth); } } static gboolean auth_idle_cb(gpointer user_data) { struct audio_device *dev = user_data; struct dev_priv *priv = dev->priv; priv->auth_idle_id = 0; auth_cb(NULL, dev); return FALSE; } static gboolean audio_device_is_connected(struct audio_device *dev) { if (dev->headset) { headset_state_t state = headset_get_state(dev); if (state == HEADSET_STATE_CONNECTED || state == HEADSET_STATE_PLAY_IN_PROGRESS || state == HEADSET_STATE_PLAYING) return TRUE; } if (dev->sink) { sink_state_t state = sink_get_state(dev); if (state == SINK_STATE_CONNECTED || state == SINK_STATE_PLAYING) return TRUE; } if (dev->source) { source_state_t state = source_get_state(dev); if (state == SOURCE_STATE_CONNECTED || state == SOURCE_STATE_PLAYING) return TRUE; } return FALSE; } int audio_device_request_authorization(struct audio_device *dev, const char *uuid, service_auth_cb cb, void *user_data) { struct dev_priv *priv = dev->priv; struct service_auth *auth; int err; auth = g_try_new0(struct service_auth, 1); if (!auth) return -ENOMEM; auth->cb = cb; auth->user_data = user_data; priv->auths = g_slist_append(priv->auths, auth); if (g_slist_length(priv->auths) > 1) return 0; if (priv->authorized || audio_device_is_connected(dev)) { priv->auth_idle_id = g_idle_add(auth_idle_cb, dev); return 0; } err = btd_request_authorization(&dev->src, &dev->dst, uuid, auth_cb, dev); if (err < 0) { priv->auths = g_slist_remove(priv->auths, auth); g_free(auth); } return err; } int audio_device_cancel_authorization(struct audio_device *dev, authorization_cb cb, void *user_data) { struct dev_priv *priv = dev->priv; GSList *l, *next; for (l = priv->auths; l != NULL; l = next) { struct service_auth *auth = l->data; next = g_slist_next(l); if (cb && auth->cb != cb) continue; if (user_data && auth->user_data != user_data) continue; priv->auths = g_slist_remove(priv->auths, auth); g_free(auth); } if (g_slist_length(priv->auths) == 0) { if (priv->auth_idle_id > 0) { g_source_remove(priv->auth_idle_id); priv->auth_idle_id = 0; } else btd_cancel_authorization(&dev->src, &dev->dst); } return 0; } void audio_device_set_authorized(struct audio_device *dev, gboolean auth) { struct dev_priv *priv = dev->priv; priv->authorized = auth; } bluez-4.101/audio/control.c0000644000000000000000000001520311766125764012474 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2011 Texas Instruments, Inc. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "error.h" #include "device.h" #include "manager.h" #include "avctp.h" #include "control.h" #include "sdpd.h" #include "glib-helper.h" #include "dbus-common.h" static unsigned int avctp_id = 0; struct control { struct audio_device *dev; struct avctp *session; gboolean target; }; static void state_changed(struct audio_device *dev, avctp_state_t old_state, avctp_state_t new_state, void *user_data) { struct control *control = dev->control; gboolean value; switch (new_state) { case AVCTP_STATE_DISCONNECTED: control->session = NULL; if (old_state != AVCTP_STATE_CONNECTED) break; value = FALSE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_CONTROL_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_CONTROL_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &value); break; case AVCTP_STATE_CONNECTING: if (control->session) break; control->session = avctp_get(&dev->src, &dev->dst); break; case AVCTP_STATE_CONNECTED: value = TRUE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_CONTROL_INTERFACE, "Connected", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_CONTROL_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &value); break; default: return; } } static DBusMessage *control_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct control *control = device->control; DBusMessage *reply; dbus_bool_t connected; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; connected = (control->session != NULL); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, DBUS_TYPE_INVALID); return reply; } static DBusMessage *volume_up(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct control *control = device->control; int err; if (!control->session) return btd_error_not_connected(msg); if (!control->target) return btd_error_not_supported(msg); err = avctp_send_passthrough(control->session, VOL_UP_OP); if (err < 0) return btd_error_failed(msg, strerror(-err)); return dbus_message_new_method_return(msg); } static DBusMessage *volume_down(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct control *control = device->control; int err; if (!control->session) return btd_error_not_connected(msg); if (!control->target) return btd_error_not_supported(msg); err = avctp_send_passthrough(control->session, VOL_DOWN_OP); if (err < 0) return btd_error_failed(msg, strerror(-err)); return dbus_message_new_method_return(msg); } static DBusMessage *control_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; gboolean value; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Connected */ value = (device->control->session != NULL); dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value); dbus_message_iter_close_container(&iter, &dict); return reply; } static const GDBusMethodTable control_methods[] = { { GDBUS_ASYNC_METHOD("IsConnected", NULL, GDBUS_ARGS({ "connected", "b" }), control_is_connected) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), control_get_properties) }, { GDBUS_METHOD("VolumeUp", NULL, NULL, volume_up) }, { GDBUS_METHOD("VolumeDown", NULL, NULL, volume_down) }, { } }; static const GDBusSignalTable control_signals[] = { { GDBUS_DEPRECATED_SIGNAL("Connected", NULL) }, { GDBUS_DEPRECATED_SIGNAL("Disconnected", NULL) }, { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static void path_unregister(void *data) { struct audio_device *dev = data; struct control *control = dev->control; DBG("Unregistered interface %s on path %s", AUDIO_CONTROL_INTERFACE, dev->path); if (control->session) avctp_disconnect(control->session); g_free(control); dev->control = NULL; } void control_unregister(struct audio_device *dev) { g_dbus_unregister_interface(dev->conn, dev->path, AUDIO_CONTROL_INTERFACE); } void control_update(struct control *control, uint16_t uuid16) { if (uuid16 == AV_REMOTE_TARGET_SVCLASS_ID) control->target = TRUE; } struct control *control_init(struct audio_device *dev, uint16_t uuid16) { struct control *control; if (!g_dbus_register_interface(dev->conn, dev->path, AUDIO_CONTROL_INTERFACE, control_methods, control_signals, NULL, dev, path_unregister)) return NULL; DBG("Registered interface %s on path %s", AUDIO_CONTROL_INTERFACE, dev->path); control = g_new0(struct control, 1); control->dev = dev; control_update(control, uuid16); if (!avctp_id) avctp_id = avctp_add_state_cb(state_changed, NULL); return control; } gboolean control_is_active(struct audio_device *dev) { struct control *control = dev->control; if (control && control->session) return TRUE; return FALSE; } bluez-4.101/audio/pcm_bluetooth.c0000644000000000000000000013021111766125764013655 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "ipc.h" #include "sbc.h" #include "rtp.h" /* #define ENABLE_DEBUG */ #define UINT_SECS_MAX (UINT_MAX / 1000000 - 1) #define MIN_PERIOD_TIME 1 #define BUFFER_SIZE 2048 #ifdef ENABLE_DEBUG #define DBG(fmt, arg...) printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg) #else #define DBG(fmt, arg...) #endif #ifndef SOL_SCO #define SOL_SCO 17 #endif #ifndef SCO_TXBUFS #define SCO_TXBUFS 0x03 #endif #ifndef SCO_RXBUFS #define SCO_RXBUFS 0x04 #endif #ifndef MIN # define MIN(x, y) ((x) < (y) ? (x) : (y)) #endif #ifndef MAX # define MAX(x, y) ((x) > (y) ? (x) : (y)) #endif #define MAX_BITPOOL 64 #define MIN_BITPOOL 2 /* adapted from glibc sys/time.h timersub() macro */ #define priv_timespecsub(a, b, result) \ do { \ (result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \ (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \ if ((result)->tv_nsec < 0) { \ --(result)->tv_sec; \ (result)->tv_nsec += 1000000000; \ } \ } while (0) struct bluetooth_a2dp { sbc_capabilities_t sbc_capabilities; sbc_t sbc; /* Codec data */ int sbc_initialized; /* Keep track if the encoder is initialized */ unsigned int codesize; /* SBC codesize */ int samples; /* Number of encoded samples */ uint8_t buffer[BUFFER_SIZE]; /* Codec transfer buffer */ unsigned int count; /* Codec transfer buffer counter */ int nsamples; /* Cumulative number of codec samples */ uint16_t seq_num; /* Cumulative packet sequence */ int frame_count; /* Current frames in buffer*/ }; struct bluetooth_alsa_config { char device[18]; /* Address of the remote Device */ int has_device; uint8_t transport; /* Requested transport */ int has_transport; uint16_t rate; int has_rate; uint8_t channel_mode; /* A2DP only */ int has_channel_mode; uint8_t allocation_method; /* A2DP only */ int has_allocation_method; uint8_t subbands; /* A2DP only */ int has_subbands; uint8_t block_length; /* A2DP only */ int has_block_length; uint8_t bitpool; /* A2DP only */ int has_bitpool; int autoconnect; }; struct bluetooth_data { snd_pcm_ioplug_t io; struct bluetooth_alsa_config alsa_config; /* ALSA resource file parameters */ volatile snd_pcm_sframes_t hw_ptr; int transport; /* chosen transport SCO or AD2P */ unsigned int link_mtu; /* MTU for selected transport channel */ volatile struct pollfd stream; /* Audio stream filedescriptor */ struct pollfd server; /* Audio daemon filedescriptor */ uint8_t buffer[BUFFER_SIZE]; /* Encoded transfer buffer */ unsigned int count; /* Transfer buffer counter */ struct bluetooth_a2dp a2dp; /* A2DP data */ pthread_t hw_thread; /* Makes virtual hw pointer move */ int pipefd[2]; /* Inter thread communication */ int stopped; sig_atomic_t reset; /* Request XRUN handling */ }; static int audioservice_send(int sk, const bt_audio_msg_header_t *msg); static int audioservice_expect(int sk, bt_audio_msg_header_t *outmsg, int expected_type); static int bluetooth_start(snd_pcm_ioplug_t *io) { DBG("bluetooth_start %p", io); return 0; } static int bluetooth_stop(snd_pcm_ioplug_t *io) { DBG("bluetooth_stop %p", io); return 0; } static void *playback_hw_thread(void *param) { struct bluetooth_data *data = param; unsigned int prev_periods; double period_time; struct timespec start; struct pollfd fds[2]; int poll_timeout; data->server.events = POLLIN; /* note: only errors for data->stream.events */ fds[0] = data->server; fds[1] = data->stream; prev_periods = 0; period_time = 1000000.0 * data->io.period_size / data->io.rate; if (period_time > (int) (MIN_PERIOD_TIME * 1000)) poll_timeout = (int) (period_time / 1000.0f); else poll_timeout = MIN_PERIOD_TIME; clock_gettime(CLOCK_MONOTONIC, &start); while (1) { unsigned int dtime, periods; struct timespec cur, delta; int ret; if (data->stopped) goto iter_sleep; if (data->reset) { DBG("Handle XRUN in hw-thread."); data->reset = 0; clock_gettime(CLOCK_MONOTONIC, &start); prev_periods = 0; } clock_gettime(CLOCK_MONOTONIC, &cur); priv_timespecsub(&cur, &start, &delta); dtime = delta.tv_sec * 1000000 + delta.tv_nsec / 1000; periods = 1.0 * dtime / period_time; if (periods > prev_periods) { char c = 'w'; int frags = periods - prev_periods, n; data->hw_ptr += frags * data->io.period_size; data->hw_ptr %= data->io.buffer_size; for (n = 0; n < frags; n++) { /* Notify user that hardware pointer * has moved * */ if (write(data->pipefd[1], &c, 1) < 0) pthread_testcancel(); } /* Reset point of reference to avoid too big values * that wont fit an unsigned int */ if ((unsigned int) delta.tv_sec < UINT_SECS_MAX) prev_periods = periods; else { prev_periods = 0; clock_gettime(CLOCK_MONOTONIC, &start); } } iter_sleep: /* sleep up to one period interval */ ret = poll(fds, 2, poll_timeout); if (ret < 0) { if (errno != EINTR) { SNDERR("poll error: %s (%d)", strerror(errno), errno); break; } } else if (ret > 0) { ret = (fds[0].revents) ? 0 : 1; SNDERR("poll fd %d revents %d", ret, fds[ret].revents); if (fds[ret].revents & (POLLERR | POLLHUP | POLLNVAL)) break; } /* Offer opportunity to be canceled by main thread */ pthread_testcancel(); } data->hw_thread = 0; pthread_exit(NULL); } static int bluetooth_playback_start(snd_pcm_ioplug_t *io) { struct bluetooth_data *data = io->private_data; int err; DBG("%p", io); data->stopped = 0; if (data->hw_thread) return 0; err = pthread_create(&data->hw_thread, 0, playback_hw_thread, data); return -err; } static int bluetooth_playback_stop(snd_pcm_ioplug_t *io) { struct bluetooth_data *data = io->private_data; DBG("%p", io); data->stopped = 1; return 0; } static snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io) { struct bluetooth_data *data = io->private_data; return data->hw_ptr; } static void bluetooth_exit(struct bluetooth_data *data) { struct bluetooth_a2dp *a2dp = &data->a2dp; if (data->server.fd >= 0) bt_audio_service_close(data->server.fd); if (data->stream.fd >= 0) close(data->stream.fd); if (data->hw_thread) { pthread_cancel(data->hw_thread); pthread_join(data->hw_thread, 0); } if (a2dp->sbc_initialized) sbc_finish(&a2dp->sbc); if (data->pipefd[0] > 0) close(data->pipefd[0]); if (data->pipefd[1] > 0) close(data->pipefd[1]); free(data); } static int bluetooth_close(snd_pcm_ioplug_t *io) { struct bluetooth_data *data = io->private_data; DBG("%p", io); bluetooth_exit(data); return 0; } static int bluetooth_prepare(snd_pcm_ioplug_t *io) { struct bluetooth_data *data = io->private_data; char c = 'w'; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_start_stream_req *req = (void *) buf; struct bt_start_stream_rsp *rsp = (void *) buf; struct bt_new_stream_ind *ind = (void *) buf; uint32_t period_count = io->buffer_size / io->period_size; int opt_name, err; struct timeval t = { 0, period_count }; DBG("Preparing with io->period_size=%lu io->buffer_size=%lu", io->period_size, io->buffer_size); data->reset = 0; /* As we're gonna receive messages on the server socket, we have to stop the hw thread that is polling on it, if any */ if (data->hw_thread) { pthread_cancel(data->hw_thread); pthread_join(data->hw_thread, 0); data->hw_thread = 0; } if (io->stream == SND_PCM_STREAM_PLAYBACK) /* If not null for playback, xmms doesn't display time * correctly */ data->hw_ptr = 0; else /* ALSA library is really picky on the fact hw_ptr is not null. * If it is, capture won't start */ data->hw_ptr = io->period_size; /* send start */ memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); req->h.type = BT_REQUEST; req->h.name = BT_START_STREAM; req->h.length = sizeof(*req); err = audioservice_send(data->server.fd, &req->h); if (err < 0) return err; rsp->h.length = sizeof(*rsp); err = audioservice_expect(data->server.fd, &rsp->h, BT_START_STREAM); if (err < 0) return err; ind->h.length = sizeof(*ind); err = audioservice_expect(data->server.fd, &ind->h, BT_NEW_STREAM); if (err < 0) return err; if (data->stream.fd >= 0) close(data->stream.fd); data->stream.fd = bt_audio_service_get_data_fd(data->server.fd); if (data->stream.fd < 0) { return -errno; } if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP) { opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ? SO_SNDTIMEO : SO_RCVTIMEO; if (setsockopt(data->stream.fd, SOL_SOCKET, opt_name, &t, sizeof(t)) < 0) return -errno; } else { opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ? SCO_TXBUFS : SCO_RXBUFS; if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count, sizeof(period_count)) == 0) return 0; opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ? SO_SNDBUF : SO_RCVBUF; if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count, sizeof(period_count)) == 0) return 0; /* FIXME : handle error codes */ } /* wake up any client polling at us */ if (write(data->pipefd[1], &c, 1) < 0) { err = -errno; return err; } return 0; } static int bluetooth_hsp_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) { struct bluetooth_data *data = io->private_data; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_open_req *open_req = (void *) buf; struct bt_open_rsp *open_rsp = (void *) buf; struct bt_set_configuration_req *req = (void *) buf; struct bt_set_configuration_rsp *rsp = (void *) buf; int err; DBG("Preparing with io->period_size=%lu io->buffer_size=%lu", io->period_size, io->buffer_size); memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); open_req->h.type = BT_REQUEST; open_req->h.name = BT_OPEN; open_req->h.length = sizeof(*open_req); strncpy(open_req->destination, data->alsa_config.device, 18); open_req->seid = BT_A2DP_SEID_RANGE + 1; open_req->lock = (io->stream == SND_PCM_STREAM_PLAYBACK ? BT_WRITE_LOCK : BT_READ_LOCK); err = audioservice_send(data->server.fd, &open_req->h); if (err < 0) return err; open_rsp->h.length = sizeof(*open_rsp); err = audioservice_expect(data->server.fd, &open_rsp->h, BT_OPEN); if (err < 0) return err; memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); req->h.type = BT_REQUEST; req->h.name = BT_SET_CONFIGURATION; req->h.length = sizeof(*req); req->codec.transport = BT_CAPABILITIES_TRANSPORT_SCO; req->codec.seid = BT_A2DP_SEID_RANGE + 1; req->codec.length = sizeof(pcm_capabilities_t); req->h.length += req->codec.length - sizeof(req->codec); err = audioservice_send(data->server.fd, &req->h); if (err < 0) return err; rsp->h.length = sizeof(*rsp); err = audioservice_expect(data->server.fd, &rsp->h, BT_SET_CONFIGURATION); if (err < 0) return err; data->transport = BT_CAPABILITIES_TRANSPORT_SCO; data->link_mtu = rsp->link_mtu; return 0; } static uint8_t default_bitpool(uint8_t freq, uint8_t mode) { switch (freq) { case BT_SBC_SAMPLING_FREQ_16000: case BT_SBC_SAMPLING_FREQ_32000: return 53; case BT_SBC_SAMPLING_FREQ_44100: switch (mode) { case BT_A2DP_CHANNEL_MODE_MONO: case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL: return 31; case BT_A2DP_CHANNEL_MODE_STEREO: case BT_A2DP_CHANNEL_MODE_JOINT_STEREO: return 53; default: DBG("Invalid channel mode %u", mode); return 53; } case BT_SBC_SAMPLING_FREQ_48000: switch (mode) { case BT_A2DP_CHANNEL_MODE_MONO: case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL: return 29; case BT_A2DP_CHANNEL_MODE_STEREO: case BT_A2DP_CHANNEL_MODE_JOINT_STEREO: return 51; default: DBG("Invalid channel mode %u", mode); return 51; } default: DBG("Invalid sampling freq %u", freq); return 53; } } static int bluetooth_a2dp_init(struct bluetooth_data *data, snd_pcm_hw_params_t *params) { struct bluetooth_alsa_config *cfg = &data->alsa_config; sbc_capabilities_t *cap = &data->a2dp.sbc_capabilities; unsigned int max_bitpool, min_bitpool, rate, channels; int dir; snd_pcm_hw_params_get_rate(params, &rate, &dir); snd_pcm_hw_params_get_channels(params, &channels); switch (rate) { case 48000: cap->frequency = BT_SBC_SAMPLING_FREQ_48000; break; case 44100: cap->frequency = BT_SBC_SAMPLING_FREQ_44100; break; case 32000: cap->frequency = BT_SBC_SAMPLING_FREQ_32000; break; case 16000: cap->frequency = BT_SBC_SAMPLING_FREQ_16000; break; default: DBG("Rate %d not supported", rate); return -1; } if (cfg->has_channel_mode) cap->channel_mode = cfg->channel_mode; else if (channels == 2) { if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO; else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) cap->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO; else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) cap->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL; } else { if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO; } if (!cap->channel_mode) { DBG("No supported channel modes"); return -1; } if (cfg->has_block_length) cap->block_length = cfg->block_length; else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16) cap->block_length = BT_A2DP_BLOCK_LENGTH_16; else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12) cap->block_length = BT_A2DP_BLOCK_LENGTH_12; else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_8) cap->block_length = BT_A2DP_BLOCK_LENGTH_8; else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_4) cap->block_length = BT_A2DP_BLOCK_LENGTH_4; else { DBG("No supported block lengths"); return -1; } if (cfg->has_subbands) cap->subbands = cfg->subbands; if (cap->subbands & BT_A2DP_SUBBANDS_8) cap->subbands = BT_A2DP_SUBBANDS_8; else if (cap->subbands & BT_A2DP_SUBBANDS_4) cap->subbands = BT_A2DP_SUBBANDS_4; else { DBG("No supported subbands"); return -1; } if (cfg->has_allocation_method) cap->allocation_method = cfg->allocation_method; if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS; else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR) cap->allocation_method = BT_A2DP_ALLOCATION_SNR; if (cfg->has_bitpool) min_bitpool = max_bitpool = cfg->bitpool; else { min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool); max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode), cap->max_bitpool); } cap->min_bitpool = min_bitpool; cap->max_bitpool = max_bitpool; return 0; } static void bluetooth_a2dp_setup(struct bluetooth_a2dp *a2dp) { sbc_capabilities_t active_capabilities = a2dp->sbc_capabilities; if (a2dp->sbc_initialized) sbc_reinit(&a2dp->sbc, 0); else sbc_init(&a2dp->sbc, 0); a2dp->sbc_initialized = 1; if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_16000) a2dp->sbc.frequency = SBC_FREQ_16000; if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_32000) a2dp->sbc.frequency = SBC_FREQ_32000; if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_44100) a2dp->sbc.frequency = SBC_FREQ_44100; if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_48000) a2dp->sbc.frequency = SBC_FREQ_48000; if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO) a2dp->sbc.mode = SBC_MODE_MONO; if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL; if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) a2dp->sbc.mode = SBC_MODE_STEREO; if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) a2dp->sbc.mode = SBC_MODE_JOINT_STEREO; a2dp->sbc.allocation = active_capabilities.allocation_method == BT_A2DP_ALLOCATION_SNR ? SBC_AM_SNR : SBC_AM_LOUDNESS; switch (active_capabilities.subbands) { case BT_A2DP_SUBBANDS_4: a2dp->sbc.subbands = SBC_SB_4; break; case BT_A2DP_SUBBANDS_8: a2dp->sbc.subbands = SBC_SB_8; break; } switch (active_capabilities.block_length) { case BT_A2DP_BLOCK_LENGTH_4: a2dp->sbc.blocks = SBC_BLK_4; break; case BT_A2DP_BLOCK_LENGTH_8: a2dp->sbc.blocks = SBC_BLK_8; break; case BT_A2DP_BLOCK_LENGTH_12: a2dp->sbc.blocks = SBC_BLK_12; break; case BT_A2DP_BLOCK_LENGTH_16: a2dp->sbc.blocks = SBC_BLK_16; break; } a2dp->sbc.bitpool = active_capabilities.max_bitpool; a2dp->codesize = sbc_get_codesize(&a2dp->sbc); a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); } static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io, snd_pcm_hw_params_t *params) { struct bluetooth_data *data = io->private_data; struct bluetooth_a2dp *a2dp = &data->a2dp; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_open_req *open_req = (void *) buf; struct bt_open_rsp *open_rsp = (void *) buf; struct bt_set_configuration_req *req = (void *) buf; struct bt_set_configuration_rsp *rsp = (void *) buf; int err; DBG("Preparing with io->period_size=%lu io->buffer_size=%lu", io->period_size, io->buffer_size); memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); open_req->h.type = BT_REQUEST; open_req->h.name = BT_OPEN; open_req->h.length = sizeof(*open_req); strncpy(open_req->destination, data->alsa_config.device, 18); open_req->seid = a2dp->sbc_capabilities.capability.seid; open_req->lock = (io->stream == SND_PCM_STREAM_PLAYBACK ? BT_WRITE_LOCK : BT_READ_LOCK); err = audioservice_send(data->server.fd, &open_req->h); if (err < 0) return err; open_rsp->h.length = sizeof(*open_rsp); err = audioservice_expect(data->server.fd, &open_rsp->h, BT_OPEN); if (err < 0) return err; err = bluetooth_a2dp_init(data, params); if (err < 0) return err; memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); req->h.type = BT_REQUEST; req->h.name = BT_SET_CONFIGURATION; req->h.length = sizeof(*req); memcpy(&req->codec, &a2dp->sbc_capabilities, sizeof(a2dp->sbc_capabilities)); req->codec.transport = BT_CAPABILITIES_TRANSPORT_A2DP; req->codec.length = sizeof(a2dp->sbc_capabilities); req->h.length += req->codec.length - sizeof(req->codec); err = audioservice_send(data->server.fd, &req->h); if (err < 0) return err; rsp->h.length = sizeof(*rsp); err = audioservice_expect(data->server.fd, &rsp->h, BT_SET_CONFIGURATION); if (err < 0) return err; data->transport = BT_CAPABILITIES_TRANSPORT_A2DP; data->link_mtu = rsp->link_mtu; /* Setup SBC encoder now we agree on parameters */ bluetooth_a2dp_setup(a2dp); DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n", a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks, a2dp->sbc.bitpool); return 0; } static int bluetooth_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int space) { struct bluetooth_data *data = io->private_data; assert(io); if (space < 1) return 0; pfd[0].fd = data->stream.fd; pfd[0].events = POLLIN; pfd[0].revents = 0; return 1; } static int bluetooth_poll_revents(snd_pcm_ioplug_t *io ATTRIBUTE_UNUSED, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { assert(pfds && nfds == 1 && revents); *revents = pfds[0].revents; return 0; } static int bluetooth_playback_poll_descriptors_count(snd_pcm_ioplug_t *io) { return 2; } static int bluetooth_playback_poll_descriptors(snd_pcm_ioplug_t *io, struct pollfd *pfd, unsigned int space) { struct bluetooth_data *data = io->private_data; DBG(""); assert(data->pipefd[0] >= 0); if (space < 2) return 0; pfd[0].fd = data->pipefd[0]; pfd[0].events = POLLIN; pfd[0].revents = 0; pfd[1].fd = data->stream.fd; pfd[1].events = POLLERR | POLLHUP | POLLNVAL; pfd[1].revents = 0; return 2; } static int bluetooth_playback_poll_revents(snd_pcm_ioplug_t *io, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) { static char buf[1]; DBG(""); assert(pfds); assert(nfds == 2); assert(revents); assert(pfds[0].fd >= 0); assert(pfds[1].fd >= 0); if (io->state != SND_PCM_STATE_PREPARED) if (read(pfds[0].fd, buf, 1) < 0) SYSERR("read error: %s (%d)", strerror(errno), errno); if (pfds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) io->state = SND_PCM_STATE_DISCONNECTED; *revents = (pfds[0].revents & POLLIN) ? POLLOUT : 0; return 0; } static snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) { struct bluetooth_data *data = io->private_data; snd_pcm_uframes_t frames_to_write, ret; unsigned char *buff; unsigned int frame_size = 0; int nrecv; DBG("areas->step=%u areas->first=%u offset=%lu size=%lu io->nonblock=%u", areas->step, areas->first, offset, size, io->nonblock); frame_size = areas->step / 8; if (data->count > 0) goto proceed; nrecv = recv(data->stream.fd, data->buffer, data->link_mtu, io->nonblock ? MSG_DONTWAIT : 0); if (nrecv < 0) { ret = (errno == EPIPE) ? -EIO : -errno; goto done; } if ((unsigned int) nrecv != data->link_mtu) { ret = -EIO; SNDERR(strerror(-ret)); goto done; } /* Increment hardware transmition pointer */ data->hw_ptr = (data->hw_ptr + data->link_mtu / frame_size) % io->buffer_size; proceed: buff = (unsigned char *) areas->addr + (areas->first + areas->step * offset) / 8; if ((data->count + size * frame_size) <= data->link_mtu) frames_to_write = size; else frames_to_write = (data->link_mtu - data->count) / frame_size; memcpy(buff, data->buffer + data->count, frame_size * frames_to_write); data->count += (frame_size * frames_to_write); data->count %= data->link_mtu; /* Return written frames count */ ret = frames_to_write; done: DBG("returning %lu", ret); return ret; } static snd_pcm_sframes_t bluetooth_hsp_write(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) { struct bluetooth_data *data = io->private_data; snd_pcm_sframes_t ret = 0; snd_pcm_uframes_t frames_to_read; uint8_t *buff; int rsend, frame_size; DBG("areas->step=%u areas->first=%u offset=%lu, size=%lu io->nonblock=%u", areas->step, areas->first, offset, size, io->nonblock); if (io->hw_ptr > io->appl_ptr) { ret = bluetooth_playback_stop(io); if (ret == 0) ret = -EPIPE; goto done; } frame_size = areas->step / 8; if ((data->count + size * frame_size) <= data->link_mtu) frames_to_read = size; else frames_to_read = (data->link_mtu - data->count) / frame_size; DBG("count=%d frames_to_read=%lu", data->count, frames_to_read); /* Ready for more data */ buff = (uint8_t *) areas->addr + (areas->first + areas->step * offset) / 8; memcpy(data->buffer + data->count, buff, frame_size * frames_to_read); /* Remember we have some frames in the pipe now */ data->count += frames_to_read * frame_size; if (data->count != data->link_mtu) { ret = frames_to_read; goto done; } rsend = send(data->stream.fd, data->buffer, data->link_mtu, io->nonblock ? MSG_DONTWAIT : 0); if (rsend > 0) { /* Reset count pointer */ data->count = 0; ret = frames_to_read; } else if (rsend < 0) ret = (errno == EPIPE) ? -EIO : -errno; else ret = -EIO; done: DBG("returning %ld", ret); return ret; } static snd_pcm_sframes_t bluetooth_a2dp_read(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) { snd_pcm_uframes_t ret = 0; return ret; } static int avdtp_write(struct bluetooth_data *data) { int err; struct rtp_header *header; struct rtp_payload *payload; struct bluetooth_a2dp *a2dp = &data->a2dp; header = (void *) a2dp->buffer; payload = (void *) (a2dp->buffer + sizeof(*header)); memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload)); payload->frame_count = a2dp->frame_count; header->v = 2; header->pt = 1; header->sequence_number = htons(a2dp->seq_num); header->timestamp = htonl(a2dp->nsamples); header->ssrc = htonl(1); err = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT); if (err < 0) { err = -errno; DBG("send failed: %s (%d)", strerror(-err), -err); } /* Reset buffer of data to send */ a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload); a2dp->frame_count = 0; a2dp->samples = 0; a2dp->seq_num++; return err; } static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io, const snd_pcm_channel_area_t *areas, snd_pcm_uframes_t offset, snd_pcm_uframes_t size) { struct bluetooth_data *data = io->private_data; struct bluetooth_a2dp *a2dp = &data->a2dp; snd_pcm_sframes_t ret = 0; unsigned int bytes_left; int frame_size, encoded; ssize_t written; uint8_t *buff; DBG("areas->step=%u areas->first=%u offset=%lu size=%lu", areas->step, areas->first, offset, size); DBG("hw_ptr=%lu appl_ptr=%lu diff=%lu", io->hw_ptr, io->appl_ptr, io->appl_ptr - io->hw_ptr); /* Calutate starting pointers */ frame_size = areas->step / 8; bytes_left = size * frame_size; buff = (uint8_t *) areas->addr + (areas->first + areas->step * (offset)) / 8; /* Check for underrun */ if (io->hw_ptr > io->appl_ptr) { ret = bluetooth_playback_stop(io); if (ret == 0) ret = -EPIPE; data->reset = 1; return ret; } /* Check if we should autostart */ if (io->state == SND_PCM_STATE_PREPARED) { snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t threshold; snd_pcm_sw_params_malloc(&swparams); if (!snd_pcm_sw_params_current(io->pcm, swparams) && !snd_pcm_sw_params_get_start_threshold(swparams, &threshold)) { if (io->appl_ptr >= threshold) { ret = snd_pcm_start(io->pcm); if (ret != 0) return ret; } } snd_pcm_sw_params_free(swparams); } /* Check if we have any left over data from the last write */ if (data->count > 0) { unsigned int additional_bytes_needed = a2dp->codesize - data->count; if (additional_bytes_needed > bytes_left) goto out; memcpy(data->buffer + data->count, buff, additional_bytes_needed); /* Enough data to encode (sbc wants 1k blocks) */ encoded = sbc_encode(&a2dp->sbc, data->buffer, a2dp->codesize, a2dp->buffer + a2dp->count, sizeof(a2dp->buffer) - a2dp->count, &written); if (encoded <= 0) { DBG("Encoding error %d", encoded); goto done; } /* Increment a2dp buffers */ a2dp->count += written; a2dp->frame_count++; a2dp->samples += encoded / frame_size; a2dp->nsamples += encoded / frame_size; /* No space left for another frame then send */ if (a2dp->count + written >= data->link_mtu) { avdtp_write(data); DBG("sending packet %d, count %d, link_mtu %u", a2dp->seq_num, a2dp->count, data->link_mtu); } /* Increment up buff pointer to take into account * the data processed */ buff += additional_bytes_needed; bytes_left -= additional_bytes_needed; /* Since data has been process mark it as zero */ data->count = 0; } /* Process this buffer in full chunks */ while (bytes_left >= a2dp->codesize) { /* Enough data to encode (sbc wants 1k blocks) */ encoded = sbc_encode(&a2dp->sbc, buff, a2dp->codesize, a2dp->buffer + a2dp->count, sizeof(a2dp->buffer) - a2dp->count, &written); if (encoded <= 0) { DBG("Encoding error %d", encoded); goto done; } /* Increment up buff pointer to take into account * the data processed */ buff += a2dp->codesize; bytes_left -= a2dp->codesize; /* Increment a2dp buffers */ a2dp->count += written; a2dp->frame_count++; a2dp->samples += encoded / frame_size; a2dp->nsamples += encoded / frame_size; /* No space left for another frame then send */ if (a2dp->count + written >= data->link_mtu) { avdtp_write(data); DBG("sending packet %d, count %d, link_mtu %u", a2dp->seq_num, a2dp->count, data->link_mtu); } } out: /* Copy the extra to our temp buffer for the next write */ if (bytes_left > 0) { memcpy(data->buffer + data->count, buff, bytes_left); data->count += bytes_left; bytes_left = 0; } done: DBG("returning %ld", size - bytes_left / frame_size); return size - bytes_left / frame_size; } static int bluetooth_playback_delay(snd_pcm_ioplug_t *io, snd_pcm_sframes_t *delayp) { DBG(""); /* This updates io->hw_ptr value using pointer() function */ snd_pcm_hwsync(io->pcm); *delayp = io->appl_ptr - io->hw_ptr; if ((io->state == SND_PCM_STATE_RUNNING) && (*delayp < 0)) { io->callback->stop(io); io->state = SND_PCM_STATE_XRUN; *delayp = 0; } /* This should never fail, ALSA API is really not prepared to handle a non zero return value */ return 0; } static snd_pcm_ioplug_callback_t bluetooth_hsp_playback = { .start = bluetooth_playback_start, .stop = bluetooth_playback_stop, .pointer = bluetooth_pointer, .close = bluetooth_close, .hw_params = bluetooth_hsp_hw_params, .prepare = bluetooth_prepare, .transfer = bluetooth_hsp_write, .poll_descriptors_count = bluetooth_playback_poll_descriptors_count, .poll_descriptors = bluetooth_playback_poll_descriptors, .poll_revents = bluetooth_playback_poll_revents, .delay = bluetooth_playback_delay, }; static snd_pcm_ioplug_callback_t bluetooth_hsp_capture = { .start = bluetooth_start, .stop = bluetooth_stop, .pointer = bluetooth_pointer, .close = bluetooth_close, .hw_params = bluetooth_hsp_hw_params, .prepare = bluetooth_prepare, .transfer = bluetooth_hsp_read, .poll_descriptors = bluetooth_poll_descriptors, .poll_revents = bluetooth_poll_revents, }; static snd_pcm_ioplug_callback_t bluetooth_a2dp_playback = { .start = bluetooth_playback_start, .stop = bluetooth_playback_stop, .pointer = bluetooth_pointer, .close = bluetooth_close, .hw_params = bluetooth_a2dp_hw_params, .prepare = bluetooth_prepare, .transfer = bluetooth_a2dp_write, .poll_descriptors_count = bluetooth_playback_poll_descriptors_count, .poll_descriptors = bluetooth_playback_poll_descriptors, .poll_revents = bluetooth_playback_poll_revents, .delay = bluetooth_playback_delay, }; static snd_pcm_ioplug_callback_t bluetooth_a2dp_capture = { .start = bluetooth_start, .stop = bluetooth_stop, .pointer = bluetooth_pointer, .close = bluetooth_close, .hw_params = bluetooth_a2dp_hw_params, .prepare = bluetooth_prepare, .transfer = bluetooth_a2dp_read, .poll_descriptors = bluetooth_poll_descriptors, .poll_revents = bluetooth_poll_revents, }; #define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0])) static int bluetooth_hsp_hw_constraint(snd_pcm_ioplug_t *io) { struct bluetooth_data *data = io->private_data; snd_pcm_access_t access_list[] = { SND_PCM_ACCESS_RW_INTERLEAVED, /* Mmap access is really useless fo this driver, but we * support it because some pieces of software out there * insist on using it */ SND_PCM_ACCESS_MMAP_INTERLEAVED }; unsigned int format_list[] = { SND_PCM_FORMAT_S16 }; int err; /* access type */ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, ARRAY_NELEMS(access_list), access_list); if (err < 0) return err; /* supported formats */ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, ARRAY_NELEMS(format_list), format_list); if (err < 0) return err; /* supported channels */ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, 1, 1); if (err < 0) return err; /* supported rate */ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE, 8000, 8000); if (err < 0) return err; /* supported block size */ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, data->link_mtu, data->link_mtu); if (err < 0) return err; err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS, 2, 200); if (err < 0) return err; return 0; } static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io) { struct bluetooth_data *data = io->private_data; struct bluetooth_a2dp *a2dp = &data->a2dp; struct bluetooth_alsa_config *cfg = &data->alsa_config; snd_pcm_access_t access_list[] = { SND_PCM_ACCESS_RW_INTERLEAVED, /* Mmap access is really useless fo this driver, but we * support it because some pieces of software out there * insist on using it */ SND_PCM_ACCESS_MMAP_INTERLEAVED }; unsigned int format_list[] = { SND_PCM_FORMAT_S16 }; unsigned int rate_list[4]; unsigned int rate_count; int err, min_channels, max_channels; unsigned int period_list[] = { 2048, 4096, /* e.g. 23.2msec/period (stereo 16bit at 44.1kHz) */ 8192 }; /* access type */ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS, ARRAY_NELEMS(access_list), access_list); if (err < 0) return err; /* supported formats */ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT, ARRAY_NELEMS(format_list), format_list); if (err < 0) return err; /* supported channels */ if (cfg->has_channel_mode) a2dp->sbc_capabilities.channel_mode = cfg->channel_mode; if (a2dp->sbc_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO) min_channels = 1; else min_channels = 2; if (a2dp->sbc_capabilities.channel_mode & (~BT_A2DP_CHANNEL_MODE_MONO)) max_channels = 2; else max_channels = 1; err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS, min_channels, max_channels); if (err < 0) return err; /* supported buffer sizes * (can be used as 3*8192, 6*4096, 12*2048, ...) */ err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_BUFFER_BYTES, 8192*3, 8192*3); if (err < 0) return err; /* supported block sizes: */ err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES, ARRAY_NELEMS(period_list), period_list); if (err < 0) return err; /* supported rates */ rate_count = 0; if (cfg->has_rate) { rate_list[rate_count] = cfg->rate; rate_count++; } else { if (a2dp->sbc_capabilities.frequency & BT_SBC_SAMPLING_FREQ_16000) { rate_list[rate_count] = 16000; rate_count++; } if (a2dp->sbc_capabilities.frequency & BT_SBC_SAMPLING_FREQ_32000) { rate_list[rate_count] = 32000; rate_count++; } if (a2dp->sbc_capabilities.frequency & BT_SBC_SAMPLING_FREQ_44100) { rate_list[rate_count] = 44100; rate_count++; } if (a2dp->sbc_capabilities.frequency & BT_SBC_SAMPLING_FREQ_48000) { rate_list[rate_count] = 48000; rate_count++; } } err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE, rate_count, rate_list); if (err < 0) return err; return 0; } static int bluetooth_parse_config(snd_config_t *conf, struct bluetooth_alsa_config *bt_config) { snd_config_iterator_t i, next; memset(bt_config, 0, sizeof(struct bluetooth_alsa_config)); /* Set defaults */ bt_config->autoconnect = 1; snd_config_for_each(i, next, conf) { snd_config_t *n = snd_config_iterator_entry(i); const char *id, *value; if (snd_config_get_id(n, &id) < 0) continue; if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0) continue; if (strcmp(id, "autoconnect") == 0) { int b; b = snd_config_get_bool(n); if (b < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } bt_config->autoconnect = b; continue; } if (strcmp(id, "device") == 0 || strcmp(id, "bdaddr") == 0) { if (snd_config_get_string(n, &value) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } bt_config->has_device = 1; strncpy(bt_config->device, value, 18); continue; } if (strcmp(id, "profile") == 0) { if (snd_config_get_string(n, &value) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } if (strcmp(value, "auto") == 0) { bt_config->transport = BT_CAPABILITIES_TRANSPORT_ANY; bt_config->has_transport = 1; } else if (strcmp(value, "voice") == 0 || strcmp(value, "hfp") == 0) { bt_config->transport = BT_CAPABILITIES_TRANSPORT_SCO; bt_config->has_transport = 1; } else if (strcmp(value, "hifi") == 0 || strcmp(value, "a2dp") == 0) { bt_config->transport = BT_CAPABILITIES_TRANSPORT_A2DP; bt_config->has_transport = 1; } continue; } if (strcmp(id, "rate") == 0) { if (snd_config_get_string(n, &value) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } bt_config->rate = atoi(value); bt_config->has_rate = 1; continue; } if (strcmp(id, "mode") == 0) { if (snd_config_get_string(n, &value) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } if (strcmp(value, "mono") == 0) { bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_MONO; bt_config->has_channel_mode = 1; } else if (strcmp(value, "dual") == 0) { bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL; bt_config->has_channel_mode = 1; } else if (strcmp(value, "stereo") == 0) { bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO; bt_config->has_channel_mode = 1; } else if (strcmp(value, "joint") == 0) { bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO; bt_config->has_channel_mode = 1; } continue; } if (strcmp(id, "allocation") == 0) { if (snd_config_get_string(n, &value) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } if (strcmp(value, "loudness") == 0) { bt_config->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS; bt_config->has_allocation_method = 1; } else if (strcmp(value, "snr") == 0) { bt_config->allocation_method = BT_A2DP_ALLOCATION_SNR; bt_config->has_allocation_method = 1; } continue; } if (strcmp(id, "subbands") == 0) { if (snd_config_get_string(n, &value) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } bt_config->subbands = atoi(value); bt_config->has_subbands = 1; continue; } if (strcmp(id, "blocks") == 0) { if (snd_config_get_string(n, &value) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } bt_config->block_length = atoi(value); bt_config->has_block_length = 1; continue; } if (strcmp(id, "bitpool") == 0) { if (snd_config_get_string(n, &value) < 0) { SNDERR("Invalid type for %s", id); return -EINVAL; } bt_config->bitpool = atoi(value); bt_config->has_bitpool = 1; continue; } SNDERR("Unknown field %s", id); return -EINVAL; } return 0; } static int audioservice_send(int sk, const bt_audio_msg_header_t *msg) { int err; uint16_t length; length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE; DBG("sending %s:%s", bt_audio_strtype(msg->type), bt_audio_strname(msg->name)); if (send(sk, msg, length, 0) > 0) err = 0; else { err = -errno; SNDERR("Error sending data to audio service: %s(%d)", strerror(-err), -err); } return err; } static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg) { int err; ssize_t ret; const char *type, *name; uint16_t length; length = inmsg->length ? inmsg->length : BT_SUGGESTED_BUFFER_SIZE; DBG("trying to receive msg from audio service..."); ret = recv(sk, inmsg, length, 0); if (ret < 0) { err = -errno; SNDERR("Error receiving IPC data from bluetoothd: %s (%d)", strerror(-err), -err); } else if ((size_t) ret < sizeof(bt_audio_msg_header_t)) { SNDERR("Too short (%d bytes) IPC packet from bluetoothd", ret); err = -EINVAL; } else { type = bt_audio_strtype(inmsg->type); name = bt_audio_strname(inmsg->name); if (type && name) { DBG("Received %s - %s", type, name); err = 0; } else { err = -EINVAL; SNDERR("Bogus message type %d - name %d" " received from audio service", inmsg->type, inmsg->name); } } return err; } static int audioservice_expect(int sk, bt_audio_msg_header_t *rsp, int expected_name) { bt_audio_error_t *error; int err = audioservice_recv(sk, rsp); if (err != 0) return err; if (rsp->name != expected_name) { err = -EINVAL; SNDERR("Bogus message %s received while %s was expected", bt_audio_strname(rsp->name), bt_audio_strname(expected_name)); } if (rsp->type == BT_ERROR) { error = (void *) rsp; SNDERR("%s failed : %s(%d)", bt_audio_strname(rsp->name), strerror(error->posix_errno), error->posix_errno); return -error->posix_errno; } return err; } static int bluetooth_parse_capabilities(struct bluetooth_data *data, struct bt_get_capabilities_rsp *rsp) { int bytes_left = rsp->h.length - sizeof(*rsp); codec_capabilities_t *codec = (void *) rsp->data; data->transport = codec->transport; if (codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP) return 0; while (bytes_left > 0) { if ((codec->type == BT_A2DP_SBC_SINK) && !(codec->lock & BT_WRITE_LOCK)) break; bytes_left -= codec->length; codec = (void *) codec + codec->length; } if (bytes_left <= 0 || codec->length != sizeof(data->a2dp.sbc_capabilities)) return -EINVAL; memcpy(&data->a2dp.sbc_capabilities, codec, codec->length); return 0; } static int bluetooth_init(struct bluetooth_data *data, snd_pcm_stream_t stream, snd_config_t *conf) { int sk, err; struct bluetooth_alsa_config *alsa_conf = &data->alsa_config; char buf[BT_SUGGESTED_BUFFER_SIZE]; struct bt_get_capabilities_req *req = (void *) buf; struct bt_get_capabilities_rsp *rsp = (void *) buf; memset(data, 0, sizeof(struct bluetooth_data)); err = bluetooth_parse_config(conf, alsa_conf); if (err < 0) return err; data->server.fd = -1; data->stream.fd = -1; sk = bt_audio_service_open(); if (sk < 0) { err = -errno; goto failed; } data->server.fd = sk; data->server.events = POLLIN; data->pipefd[0] = -1; data->pipefd[1] = -1; if (pipe(data->pipefd) < 0) { err = -errno; goto failed; } if (fcntl(data->pipefd[0], F_SETFL, O_NONBLOCK) < 0) { err = -errno; goto failed; } if (fcntl(data->pipefd[1], F_SETFL, O_NONBLOCK) < 0) { err = -errno; goto failed; } memset(req, 0, BT_SUGGESTED_BUFFER_SIZE); req->h.type = BT_REQUEST; req->h.name = BT_GET_CAPABILITIES; req->h.length = sizeof(*req); if (alsa_conf->autoconnect) req->flags |= BT_FLAG_AUTOCONNECT; strncpy(req->destination, alsa_conf->device, 18); if (alsa_conf->has_transport) req->transport = alsa_conf->transport; else req->transport = BT_CAPABILITIES_TRANSPORT_ANY; err = audioservice_send(data->server.fd, &req->h); if (err < 0) goto failed; rsp->h.length = 0; err = audioservice_expect(data->server.fd, &rsp->h, BT_GET_CAPABILITIES); if (err < 0) goto failed; bluetooth_parse_capabilities(data, rsp); return 0; failed: if (sk >= 0) bt_audio_service_close(sk); return err; } SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth); SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth) { struct bluetooth_data *data; int err; DBG("Bluetooth PCM plugin (%s)", stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture"); data = malloc(sizeof(struct bluetooth_data)); if (!data) { err = -ENOMEM; goto error; } err = bluetooth_init(data, stream, conf); if (err < 0) goto error; data->io.version = SND_PCM_IOPLUG_VERSION; data->io.name = "Bluetooth Audio Device"; data->io.mmap_rw = 0; /* No direct mmap communication */ data->io.private_data = data; if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP) data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ? &bluetooth_a2dp_playback : &bluetooth_a2dp_capture; else data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ? &bluetooth_hsp_playback : &bluetooth_hsp_capture; err = snd_pcm_ioplug_create(&data->io, name, stream, mode); if (err < 0) goto error; if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP) err = bluetooth_a2dp_hw_constraint(&data->io); else err = bluetooth_hsp_hw_constraint(&data->io); if (err < 0) { snd_pcm_ioplug_delete(&data->io); goto error; } *pcmp = data->io.pcm; return 0; error: if (data) bluetooth_exit(data); return err; } SND_PCM_PLUGIN_SYMBOL(bluetooth); bluez-4.101/audio/gateway.h0000644000000000000000000000544311766125764012467 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define AUDIO_GATEWAY_INTERFACE "org.bluez.HandsfreeGateway" #define DEFAULT_HFP_HS_CHANNEL 7 typedef enum { GATEWAY_STATE_DISCONNECTED, GATEWAY_STATE_CONNECTING, GATEWAY_STATE_CONNECTED, GATEWAY_STATE_PLAYING, } gateway_state_t; typedef enum { GATEWAY_LOCK_READ = 1, GATEWAY_LOCK_WRITE = 1 << 1, } gateway_lock_t; typedef enum { GATEWAY_ERROR_DISCONNECTED, GATEWAY_ERROR_SUSPENDED, } gateway_error_t; #define GATEWAY_ERROR gateway_error_quark() GQuark gateway_error_quark(void); typedef void (*gateway_state_cb) (struct audio_device *dev, gateway_state_t old_state, gateway_state_t new_state, void *user_data); typedef void (*gateway_stream_cb_t) (struct audio_device *dev, GError *err, void *user_data); void gateway_set_state(struct audio_device *dev, gateway_state_t new_state); void gateway_unregister(struct audio_device *dev); struct gateway *gateway_init(struct audio_device *device); gboolean gateway_is_active(struct audio_device *dev); gboolean gateway_is_connected(struct audio_device *dev); int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io); int gateway_connect_sco(struct audio_device *dev, GIOChannel *chan); void gateway_start_service(struct audio_device *device); unsigned int gateway_request_stream(struct audio_device *dev, gateway_stream_cb_t cb, void *user_data); int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t cb, void *user_data); gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id); int gateway_get_sco_fd(struct audio_device *dev); void gateway_suspend_stream(struct audio_device *dev); unsigned int gateway_add_state_cb(gateway_state_cb cb, void *user_data); gboolean gateway_remove_state_cb(unsigned int id); gateway_lock_t gateway_get_lock(struct audio_device *dev); gboolean gateway_lock(struct audio_device *dev, gateway_lock_t lock); gboolean gateway_unlock(struct audio_device *dev, gateway_lock_t lock); bluez-4.101/audio/ipc.c0000644000000000000000000000604111766125764011567 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "ipc.h" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /* This table contains the string representation for messages types */ static const char *strtypes[] = { "BT_REQUEST", "BT_RESPONSE", "BT_INDICATION", "BT_ERROR", }; /* This table contains the string representation for messages names */ static const char *strnames[] = { "BT_GET_CAPABILITIES", "BT_OPEN", "BT_SET_CONFIGURATION", "BT_NEW_STREAM", "BT_START_STREAM", "BT_STOP_STREAM", "BT_SUSPEND_STREAM", "BT_RESUME_STREAM", "BT_CONTROL", }; int bt_audio_service_open(void) { int sk; int err; struct sockaddr_un addr = { AF_UNIX, BT_IPC_SOCKET_NAME }; sk = socket(PF_LOCAL, SOCK_STREAM, 0); if (sk < 0) { err = -errno; fprintf(stderr, "%s: Cannot open socket: %s (%d)\n", __FUNCTION__, strerror(-err), -err); errno = -err; return -1; } if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { err = -errno; fprintf(stderr, "%s: connect() failed: %s (%d)\n", __FUNCTION__, strerror(-err), -err); close(sk); errno = -err; return -1; } return sk; } int bt_audio_service_close(int sk) { return close(sk); } int bt_audio_service_get_data_fd(int sk) { char cmsg_b[CMSG_SPACE(sizeof(int))], m; int err, ret; struct iovec iov = { &m, sizeof(m) }; struct msghdr msgh; struct cmsghdr *cmsg; memset(&msgh, 0, sizeof(msgh)); msgh.msg_iov = &iov; msgh.msg_iovlen = 1; msgh.msg_control = &cmsg_b; msgh.msg_controllen = CMSG_LEN(sizeof(int)); ret = recvmsg(sk, &msgh, 0); if (ret < 0) { err = -errno; fprintf(stderr, "%s: Unable to receive fd: %s (%d)\n", __FUNCTION__, strerror(-err), -err); errno = -err; return -1; } /* Receive auxiliary data in msgh */ for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(&msgh, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { memcpy(&ret, CMSG_DATA(cmsg), sizeof(int)); return ret; } } errno = EINVAL; return -1; } const char *bt_audio_strtype(uint8_t type) { if (type >= ARRAY_SIZE(strtypes)) return NULL; return strtypes[type]; } const char *bt_audio_strname(uint8_t name) { if (name >= ARRAY_SIZE(strnames)) return NULL; return strnames[name]; } bluez-4.101/audio/gsta2dpsink.c0000644000000000000000000004532611766125764013256 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "gstpragma.h" #include "gsta2dpsink.h" GST_DEBUG_CATEGORY_STATIC(gst_a2dp_sink_debug); #define GST_CAT_DEFAULT gst_a2dp_sink_debug #define A2DP_SBC_RTP_PAYLOAD_TYPE 1 #define TEMPLATE_MAX_BITPOOL_STR "64" #define DEFAULT_AUTOCONNECT TRUE enum { PROP_0, PROP_DEVICE, PROP_AUTOCONNECT, PROP_TRANSPORT }; GST_BOILERPLATE(GstA2dpSink, gst_a2dp_sink, GstBin, GST_TYPE_BIN); static const GstElementDetails gst_a2dp_sink_details = GST_ELEMENT_DETAILS("Bluetooth A2DP sink", "Sink/Audio", "Plays audio to an A2DP device", "Marcel Holtmann "); static GstStaticPadTemplate gst_a2dp_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-sbc, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, " "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " "allocation = (string) { \"snr\", \"loudness\" }, " "bitpool = (int) [ 2, " TEMPLATE_MAX_BITPOOL_STR " ]; " "audio/mpeg" )); static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event); static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps); static GstCaps *gst_a2dp_sink_get_caps(GstPad *pad); static gboolean gst_a2dp_sink_init_caps_filter(GstA2dpSink *self); static gboolean gst_a2dp_sink_init_fakesink(GstA2dpSink *self); static gboolean gst_a2dp_sink_remove_fakesink(GstA2dpSink *self); static void gst_a2dp_sink_finalize(GObject *obj) { GstA2dpSink *self = GST_A2DP_SINK(obj); g_mutex_free(self->cb_mutex); G_OBJECT_CLASS(parent_class)->finalize(obj); } static GstState gst_a2dp_sink_get_state(GstA2dpSink *self) { GstState current, pending; gst_element_get_state(GST_ELEMENT(self), ¤t, &pending, 0); if (pending == GST_STATE_VOID_PENDING) return current; return pending; } /* * Helper function to create elements, add to the bin and link it * to another element. */ static GstElement *gst_a2dp_sink_init_element(GstA2dpSink *self, const gchar *elementname, const gchar *name, GstElement *link_to) { GstElement *element; GstState state; GST_LOG_OBJECT(self, "Initializing %s", elementname); element = gst_element_factory_make(elementname, name); if (element == NULL) { GST_DEBUG_OBJECT(self, "Couldn't create %s", elementname); return NULL; } if (!gst_bin_add(GST_BIN(self), element)) { GST_DEBUG_OBJECT(self, "failed to add %s to the bin", elementname); goto cleanup_and_fail; } state = gst_a2dp_sink_get_state(self); if (gst_element_set_state(element, state) == GST_STATE_CHANGE_FAILURE) { GST_DEBUG_OBJECT(self, "%s failed to go to playing", elementname); goto remove_element_and_fail; } if (link_to != NULL) if (!gst_element_link(link_to, element)) { GST_DEBUG_OBJECT(self, "couldn't link %s", elementname); goto remove_element_and_fail; } return element; remove_element_and_fail: gst_element_set_state(element, GST_STATE_NULL); gst_bin_remove(GST_BIN(self), element); return NULL; cleanup_and_fail: g_object_unref(G_OBJECT(element)); return NULL; } static void gst_a2dp_sink_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); gst_element_class_set_details(element_class, &gst_a2dp_sink_details); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&gst_a2dp_sink_factory)); } static void gst_a2dp_sink_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstA2dpSink *self = GST_A2DP_SINK(object); switch (prop_id) { case PROP_DEVICE: if (self->sink != NULL) gst_avdtp_sink_set_device(self->sink, g_value_get_string(value)); if (self->device != NULL) g_free(self->device); self->device = g_value_dup_string(value); break; case PROP_TRANSPORT: if (self->sink != NULL) gst_avdtp_sink_set_transport(self->sink, g_value_get_string(value)); if (self->transport != NULL) g_free(self->transport); self->transport = g_value_dup_string(value); break; case PROP_AUTOCONNECT: self->autoconnect = g_value_get_boolean(value); if (self->sink != NULL) g_object_set(G_OBJECT(self->sink), "auto-connect", self->autoconnect, NULL); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_a2dp_sink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstA2dpSink *self = GST_A2DP_SINK(object); gchar *device, *transport; switch (prop_id) { case PROP_DEVICE: if (self->sink != NULL) { device = gst_avdtp_sink_get_device(self->sink); if (device != NULL) g_value_take_string(value, device); } break; case PROP_AUTOCONNECT: if (self->sink != NULL) g_object_get(G_OBJECT(self->sink), "auto-connect", &self->autoconnect, NULL); g_value_set_boolean(value, self->autoconnect); break; case PROP_TRANSPORT: if (self->sink != NULL) { transport = gst_avdtp_sink_get_transport(self->sink); if (transport != NULL) g_value_take_string(value, transport); } break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static gboolean gst_a2dp_sink_init_ghost_pad(GstA2dpSink *self) { GstPad *capsfilter_pad; /* we search for the capsfilter sinkpad */ capsfilter_pad = gst_element_get_static_pad(self->capsfilter, "sink"); /* now we add a ghostpad */ self->ghostpad = GST_GHOST_PAD(gst_ghost_pad_new("sink", capsfilter_pad)); g_object_unref(capsfilter_pad); /* the getcaps of our ghostpad must reflect the device caps */ gst_pad_set_getcaps_function(GST_PAD(self->ghostpad), gst_a2dp_sink_get_caps); self->ghostpad_setcapsfunc = GST_PAD_SETCAPSFUNC(self->ghostpad); gst_pad_set_setcaps_function(GST_PAD(self->ghostpad), GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_caps)); /* we need to handle events on our own and we also need the eventfunc * of the ghostpad for forwarding calls */ self->ghostpad_eventfunc = GST_PAD_EVENTFUNC(GST_PAD(self->ghostpad)); gst_pad_set_event_function(GST_PAD(self->ghostpad), gst_a2dp_sink_handle_event); if (!gst_element_add_pad(GST_ELEMENT(self), GST_PAD(self->ghostpad))) GST_ERROR_OBJECT(self, "failed to add ghostpad"); return TRUE; } static void gst_a2dp_sink_remove_dynamic_elements(GstA2dpSink *self) { if (self->rtp) { GST_LOG_OBJECT(self, "removing rtp element from the bin"); if (!gst_bin_remove(GST_BIN(self), GST_ELEMENT(self->rtp))) GST_WARNING_OBJECT(self, "failed to remove rtp " "element from bin"); else self->rtp = NULL; } } static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element, GstStateChange transition) { GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GstA2dpSink *self = GST_A2DP_SINK(element); switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: self->taglist = gst_tag_list_new(); gst_a2dp_sink_init_fakesink(self); break; case GST_STATE_CHANGE_NULL_TO_READY: self->sink_is_in_bin = FALSE; self->sink = GST_AVDTP_SINK(gst_element_factory_make( "avdtpsink", "avdtpsink")); if (self->sink == NULL) { GST_WARNING_OBJECT(self, "failed to create avdtpsink"); return GST_STATE_CHANGE_FAILURE; } if (self->device != NULL) gst_avdtp_sink_set_device(self->sink, self->device); if (self->transport != NULL) gst_avdtp_sink_set_transport(self->sink, self->transport); g_object_set(G_OBJECT(self->sink), "auto-connect", self->autoconnect, NULL); ret = gst_element_set_state(GST_ELEMENT(self->sink), GST_STATE_READY); break; default: break; } if (ret == GST_STATE_CHANGE_FAILURE) return ret; ret = GST_ELEMENT_CLASS(parent_class)->change_state(element, transition); switch (transition) { case GST_STATE_CHANGE_PAUSED_TO_READY: if (self->taglist) { gst_tag_list_free(self->taglist); self->taglist = NULL; } if (self->newseg_event != NULL) { gst_event_unref(self->newseg_event); self->newseg_event = NULL; } gst_a2dp_sink_remove_fakesink(self); break; case GST_STATE_CHANGE_READY_TO_NULL: if (self->sink_is_in_bin) { if (!gst_bin_remove(GST_BIN(self), GST_ELEMENT(self->sink))) GST_WARNING_OBJECT(self, "Failed to remove " "avdtpsink from bin"); } else if (self->sink != NULL) { gst_element_set_state(GST_ELEMENT(self->sink), GST_STATE_NULL); g_object_unref(G_OBJECT(self->sink)); } self->sink = NULL; gst_a2dp_sink_remove_dynamic_elements(self); break; default: break; } return ret; } static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); GstElementClass *element_class = GST_ELEMENT_CLASS(klass); parent_class = g_type_class_peek_parent(klass); object_class->set_property = GST_DEBUG_FUNCPTR( gst_a2dp_sink_set_property); object_class->get_property = GST_DEBUG_FUNCPTR( gst_a2dp_sink_get_property); object_class->finalize = GST_DEBUG_FUNCPTR( gst_a2dp_sink_finalize); element_class->change_state = GST_DEBUG_FUNCPTR( gst_a2dp_sink_change_state); g_object_class_install_property(object_class, PROP_DEVICE, g_param_spec_string("device", "Device", "Bluetooth remote device address", NULL, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_AUTOCONNECT, g_param_spec_boolean("auto-connect", "Auto-connect", "Automatically attempt to connect to device", DEFAULT_AUTOCONNECT, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_TRANSPORT, g_param_spec_string("transport", "Transport", "Use configured transport", NULL, G_PARAM_READWRITE)); GST_DEBUG_CATEGORY_INIT(gst_a2dp_sink_debug, "a2dpsink", 0, "A2DP sink element"); } GstCaps *gst_a2dp_sink_get_device_caps(GstA2dpSink *self) { return gst_avdtp_sink_get_device_caps(self->sink); } static GstCaps *gst_a2dp_sink_get_caps(GstPad *pad) { GstCaps *caps; GstCaps *caps_aux; GstA2dpSink *self = GST_A2DP_SINK(GST_PAD_PARENT(pad)); if (self->sink == NULL) { GST_DEBUG_OBJECT(self, "a2dpsink isn't initialized " "returning template caps"); caps = gst_static_pad_template_get_caps( &gst_a2dp_sink_factory); } else { GST_LOG_OBJECT(self, "Getting device caps"); caps = gst_a2dp_sink_get_device_caps(self); if (caps == NULL) caps = gst_static_pad_template_get_caps( &gst_a2dp_sink_factory); } caps_aux = gst_caps_copy(caps); g_object_set(self->capsfilter, "caps", caps_aux, NULL); gst_caps_unref(caps_aux); return caps; } static gboolean gst_a2dp_sink_init_avdtp_sink(GstA2dpSink *self) { GstElement *sink; /* check if we don't need a new sink */ if (self->sink_is_in_bin) return TRUE; if (self->sink == NULL) sink = gst_element_factory_make("avdtpsink", "avdtpsink"); else sink = GST_ELEMENT(self->sink); if (sink == NULL) { GST_ERROR_OBJECT(self, "Couldn't create avdtpsink"); return FALSE; } if (!gst_bin_add(GST_BIN(self), sink)) { GST_ERROR_OBJECT(self, "failed to add avdtpsink " "to the bin"); goto cleanup_and_fail; } if (gst_element_set_state(sink, GST_STATE_READY) == GST_STATE_CHANGE_FAILURE) { GST_ERROR_OBJECT(self, "avdtpsink failed to go to ready"); goto remove_element_and_fail; } if (!gst_element_link(GST_ELEMENT(self->rtp), sink)) { GST_ERROR_OBJECT(self, "couldn't link rtpsbcpay " "to avdtpsink"); goto remove_element_and_fail; } self->sink = GST_AVDTP_SINK(sink); self->sink_is_in_bin = TRUE; g_object_set(G_OBJECT(self->sink), "device", self->device, NULL); g_object_set(G_OBJECT(self->sink), "transport", self->transport, NULL); gst_element_set_state(sink, GST_STATE_PAUSED); return TRUE; remove_element_and_fail: gst_element_set_state(sink, GST_STATE_NULL); gst_bin_remove(GST_BIN(self), sink); return FALSE; cleanup_and_fail: if (sink != NULL) g_object_unref(G_OBJECT(sink)); return FALSE; } static gboolean gst_a2dp_sink_init_rtp_sbc_element(GstA2dpSink *self) { GstElement *rtppay; /* if we already have a rtp, we don't need a new one */ if (self->rtp != NULL) return TRUE; rtppay = gst_a2dp_sink_init_element(self, "rtpsbcpay", "rtp", self->capsfilter); if (rtppay == NULL) return FALSE; self->rtp = GST_BASE_RTP_PAYLOAD(rtppay); g_object_set(G_OBJECT(self->rtp), "min-frames", -1, NULL); gst_element_set_state(rtppay, GST_STATE_PAUSED); return TRUE; } static gboolean gst_a2dp_sink_init_rtp_mpeg_element(GstA2dpSink *self) { GstElement *rtppay; /* check if we don't need a new rtp */ if (self->rtp) return TRUE; GST_LOG_OBJECT(self, "Initializing rtp mpeg element"); /* if capsfilter is not created then we can't have our rtp element */ if (self->capsfilter == NULL) return FALSE; rtppay = gst_a2dp_sink_init_element(self, "rtpmpapay", "rtp", self->capsfilter); if (rtppay == NULL) return FALSE; self->rtp = GST_BASE_RTP_PAYLOAD(rtppay); gst_element_set_state(rtppay, GST_STATE_PAUSED); return TRUE; } static gboolean gst_a2dp_sink_init_dynamic_elements(GstA2dpSink *self, GstCaps *caps) { GstStructure *structure; GstEvent *event; GstPad *capsfilterpad; gboolean crc; gchar *mode = NULL; structure = gst_caps_get_structure(caps, 0); /* before everything we need to remove fakesink */ gst_a2dp_sink_remove_fakesink(self); /* first, we need to create our rtp payloader */ if (gst_structure_has_name(structure, "audio/x-sbc")) { GST_LOG_OBJECT(self, "sbc media received"); if (!gst_a2dp_sink_init_rtp_sbc_element(self)) return FALSE; } else if (gst_structure_has_name(structure, "audio/mpeg")) { GST_LOG_OBJECT(self, "mp3 media received"); if (!gst_a2dp_sink_init_rtp_mpeg_element(self)) return FALSE; } else { GST_ERROR_OBJECT(self, "Unexpected media type"); return FALSE; } if (!gst_a2dp_sink_init_avdtp_sink(self)) return FALSE; /* check if we should push the taglist FIXME should we push this? * we can send the tags directly if needed */ if (self->taglist != NULL && gst_structure_has_name(structure, "audio/mpeg")) { event = gst_event_new_tag(self->taglist); /* send directly the crc */ if (gst_tag_list_get_boolean(self->taglist, "has-crc", &crc)) gst_avdtp_sink_set_crc(self->sink, crc); if (gst_tag_list_get_string(self->taglist, "channel-mode", &mode)) gst_avdtp_sink_set_channel_mode(self->sink, mode); capsfilterpad = gst_ghost_pad_get_target(self->ghostpad); gst_pad_send_event(capsfilterpad, event); self->taglist = NULL; g_free(mode); } if (!gst_avdtp_sink_set_device_caps(self->sink, caps)) return FALSE; g_object_set(G_OBJECT(self->rtp), "mtu", gst_avdtp_sink_get_link_mtu(self->sink), NULL); /* we forward our new segment here if we have one */ if (self->newseg_event) { gst_pad_send_event(GST_BASE_RTP_PAYLOAD_SINKPAD(self->rtp), self->newseg_event); self->newseg_event = NULL; } return TRUE; } static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps) { GstA2dpSink *self; self = GST_A2DP_SINK(GST_PAD_PARENT(pad)); GST_INFO_OBJECT(self, "setting caps"); /* now we know the caps */ gst_a2dp_sink_init_dynamic_elements(self, caps); return self->ghostpad_setcapsfunc(GST_PAD(self->ghostpad), caps); } /* used for catching newsegment events while we don't have a sink, for * later forwarding it to the sink */ static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event) { GstA2dpSink *self; GstTagList *taglist = NULL; GstObject *parent; self = GST_A2DP_SINK(GST_PAD_PARENT(pad)); parent = gst_element_get_parent(GST_ELEMENT(self->sink)); if (GST_EVENT_TYPE(event) == GST_EVENT_NEWSEGMENT && parent != GST_OBJECT_CAST(self)) { if (self->newseg_event != NULL) gst_event_unref(self->newseg_event); self->newseg_event = gst_event_ref(event); } else if (GST_EVENT_TYPE(event) == GST_EVENT_TAG && parent != GST_OBJECT_CAST(self)) { if (self->taglist == NULL) gst_event_parse_tag(event, &self->taglist); else { gst_event_parse_tag(event, &taglist); gst_tag_list_insert(self->taglist, taglist, GST_TAG_MERGE_REPLACE); } } if (parent != NULL) gst_object_unref(GST_OBJECT(parent)); return self->ghostpad_eventfunc(GST_PAD(self->ghostpad), event); } static gboolean gst_a2dp_sink_init_caps_filter(GstA2dpSink *self) { GstElement *element; element = gst_element_factory_make("capsfilter", "filter"); if (element == NULL) goto failed; if (!gst_bin_add(GST_BIN(self), element)) goto failed; self->capsfilter = element; return TRUE; failed: GST_ERROR_OBJECT(self, "Failed to initialize caps filter"); return FALSE; } static gboolean gst_a2dp_sink_init_fakesink(GstA2dpSink *self) { if (self->fakesink != NULL) return TRUE; g_mutex_lock(self->cb_mutex); self->fakesink = gst_a2dp_sink_init_element(self, "fakesink", "fakesink", self->capsfilter); g_mutex_unlock(self->cb_mutex); if (!self->fakesink) return FALSE; return TRUE; } static gboolean gst_a2dp_sink_remove_fakesink(GstA2dpSink *self) { g_mutex_lock(self->cb_mutex); if (self->fakesink != NULL) { gst_element_set_locked_state(self->fakesink, TRUE); gst_element_set_state(self->fakesink, GST_STATE_NULL); gst_bin_remove(GST_BIN(self), self->fakesink); self->fakesink = NULL; } g_mutex_unlock(self->cb_mutex); return TRUE; } static void gst_a2dp_sink_init(GstA2dpSink *self, GstA2dpSinkClass *klass) { self->sink = NULL; self->fakesink = NULL; self->rtp = NULL; self->device = NULL; self->transport = NULL; self->autoconnect = DEFAULT_AUTOCONNECT; self->capsfilter = NULL; self->newseg_event = NULL; self->taglist = NULL; self->ghostpad = NULL; self->sink_is_in_bin = FALSE; self->cb_mutex = g_mutex_new(); /* we initialize our capsfilter */ gst_a2dp_sink_init_caps_filter(self); g_object_set(self->capsfilter, "caps", gst_static_pad_template_get_caps(&gst_a2dp_sink_factory), NULL); gst_a2dp_sink_init_fakesink(self); gst_a2dp_sink_init_ghost_pad(self); } gboolean gst_a2dp_sink_plugin_init(GstPlugin *plugin) { return gst_element_register(plugin, "a2dpsink", GST_RANK_MARGINAL, GST_TYPE_A2DP_SINK); } bluez-4.101/audio/gstsbcenc.c0000644000000000000000000003677311766125764013006 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "gstpragma.h" #include "gstsbcutil.h" #include "gstsbcenc.h" #define SBC_ENC_DEFAULT_MODE SBC_MODE_AUTO #define SBC_ENC_DEFAULT_BLOCKS 0 #define SBC_ENC_DEFAULT_SUB_BANDS 0 #define SBC_ENC_DEFAULT_ALLOCATION SBC_AM_AUTO #define SBC_ENC_DEFAULT_RATE 0 #define SBC_ENC_DEFAULT_CHANNELS 0 #define SBC_ENC_BITPOOL_AUTO 1 #define SBC_ENC_BITPOOL_MIN 2 #define SBC_ENC_BITPOOL_MIN_STR "2" #define SBC_ENC_BITPOOL_MAX 64 #define SBC_ENC_BITPOOL_MAX_STR "64" GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug); #define GST_CAT_DEFAULT sbc_enc_debug #define GST_TYPE_SBC_MODE (gst_sbc_mode_get_type()) static GType gst_sbc_mode_get_type(void) { static GType sbc_mode_type = 0; static GEnumValue sbc_modes[] = { { SBC_MODE_MONO, "Mono", "mono" }, { SBC_MODE_DUAL_CHANNEL, "Dual Channel", "dual" }, { SBC_MODE_STEREO, "Stereo", "stereo"}, { SBC_MODE_JOINT_STEREO, "Joint Stereo", "joint" }, { SBC_MODE_AUTO, "Auto", "auto" }, { -1, NULL, NULL} }; if (!sbc_mode_type) sbc_mode_type = g_enum_register_static("GstSbcMode", sbc_modes); return sbc_mode_type; } #define GST_TYPE_SBC_ALLOCATION (gst_sbc_allocation_get_type()) static GType gst_sbc_allocation_get_type(void) { static GType sbc_allocation_type = 0; static GEnumValue sbc_allocations[] = { { SBC_AM_LOUDNESS, "Loudness", "loudness" }, { SBC_AM_SNR, "SNR", "snr" }, { SBC_AM_AUTO, "Auto", "auto" }, { -1, NULL, NULL} }; if (!sbc_allocation_type) sbc_allocation_type = g_enum_register_static( "GstSbcAllocation", sbc_allocations); return sbc_allocation_type; } #define GST_TYPE_SBC_BLOCKS (gst_sbc_blocks_get_type()) static GType gst_sbc_blocks_get_type(void) { static GType sbc_blocks_type = 0; static GEnumValue sbc_blocks[] = { { 0, "Auto", "auto" }, { 4, "4", "4" }, { 8, "8", "8" }, { 12, "12", "12" }, { 16, "16", "16" }, { -1, NULL, NULL} }; if (!sbc_blocks_type) sbc_blocks_type = g_enum_register_static( "GstSbcBlocks", sbc_blocks); return sbc_blocks_type; } #define GST_TYPE_SBC_SUBBANDS (gst_sbc_subbands_get_type()) static GType gst_sbc_subbands_get_type(void) { static GType sbc_subbands_type = 0; static GEnumValue sbc_subbands[] = { { 0, "Auto", "auto" }, { 4, "4 subbands", "4" }, { 8, "8 subbands", "8" }, { -1, NULL, NULL} }; if (!sbc_subbands_type) sbc_subbands_type = g_enum_register_static( "GstSbcSubbands", sbc_subbands); return sbc_subbands_type; } enum { PROP_0, PROP_MODE, PROP_ALLOCATION, PROP_BLOCKS, PROP_SUBBANDS, PROP_BITPOOL }; GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT); static const GstElementDetails sbc_enc_details = GST_ELEMENT_DETAILS("Bluetooth SBC encoder", "Codec/Encoder/Audio", "Encode a SBC audio stream", "Marcel Holtmann "); static GstStaticPadTemplate sbc_enc_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-raw-int, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " "endianness = (int) BYTE_ORDER, " "signed = (boolean) true, " "width = (int) 16, " "depth = (int) 16")); static GstStaticPadTemplate sbc_enc_src_factory = GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-sbc, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, " "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " "allocation = (string) { \"snr\", \"loudness\" }, " "bitpool = (int) [ " SBC_ENC_BITPOOL_MIN_STR ", " SBC_ENC_BITPOOL_MAX_STR " ]")); gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps); static GstCaps *sbc_enc_generate_srcpad_caps(GstSbcEnc *enc) { GstCaps *src_caps; GstStructure *structure; GEnumValue *enum_value; GEnumClass *enum_class; GValue *value; src_caps = gst_caps_copy(gst_pad_get_pad_template_caps(enc->srcpad)); structure = gst_caps_get_structure(src_caps, 0); value = g_new0(GValue, 1); if (enc->rate != 0) gst_sbc_util_set_structure_int_param(structure, "rate", enc->rate, value); if (enc->channels != 0) gst_sbc_util_set_structure_int_param(structure, "channels", enc->channels, value); if (enc->subbands != 0) gst_sbc_util_set_structure_int_param(structure, "subbands", enc->subbands, value); if (enc->blocks != 0) gst_sbc_util_set_structure_int_param(structure, "blocks", enc->blocks, value); if (enc->bitpool != SBC_ENC_BITPOOL_AUTO) gst_sbc_util_set_structure_int_param(structure, "bitpool", enc->bitpool, value); if (enc->mode != SBC_ENC_DEFAULT_MODE) { enum_class = g_type_class_ref(GST_TYPE_SBC_MODE); enum_value = g_enum_get_value(enum_class, enc->mode); gst_sbc_util_set_structure_string_param(structure, "mode", enum_value->value_nick, value); g_type_class_unref(enum_class); } if (enc->allocation != SBC_AM_AUTO) { enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION); enum_value = g_enum_get_value(enum_class, enc->allocation); gst_sbc_util_set_structure_string_param(structure, "allocation", enum_value->value_nick, value); g_type_class_unref(enum_class); } g_free(value); return src_caps; } static GstCaps *sbc_enc_src_getcaps(GstPad *pad) { GstSbcEnc *enc; enc = GST_SBC_ENC(GST_PAD_PARENT(pad)); return sbc_enc_generate_srcpad_caps(enc); } static gboolean sbc_enc_src_setcaps(GstPad *pad, GstCaps *caps) { GstSbcEnc *enc = GST_SBC_ENC(GST_PAD_PARENT(pad)); GST_LOG_OBJECT(enc, "setting srcpad caps"); return gst_sbc_enc_fill_sbc_params(enc, caps); } static GstCaps *sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps) { gchar *error_message = NULL; GstCaps *result; result = gst_sbc_util_caps_fixate(caps, &error_message); if (!result) { GST_WARNING_OBJECT(enc, "Invalid input caps caused parsing " "error: %s", error_message); g_free(error_message); return NULL; } return result; } static GstCaps *sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc) { GstCaps *caps; gboolean res = TRUE; GstCaps *result_caps = NULL; caps = gst_pad_get_allowed_caps(enc->srcpad); if (caps == NULL) caps = sbc_enc_src_getcaps(enc->srcpad); if (caps == GST_CAPS_NONE || gst_caps_is_empty(caps)) { res = FALSE; goto done; } result_caps = sbc_enc_src_caps_fixate(enc, caps); done: gst_caps_unref(caps); if (!res) return NULL; return result_caps; } static gboolean sbc_enc_sink_setcaps(GstPad *pad, GstCaps *caps) { GstSbcEnc *enc; GstStructure *structure; GstCaps *src_caps; gint rate, channels; gboolean res; enc = GST_SBC_ENC(GST_PAD_PARENT(pad)); structure = gst_caps_get_structure(caps, 0); if (!gst_structure_get_int(structure, "rate", &rate)) return FALSE; if (!gst_structure_get_int(structure, "channels", &channels)) return FALSE; enc->rate = rate; enc->channels = channels; src_caps = sbc_enc_get_fixed_srcpad_caps(enc); if (!src_caps) return FALSE; res = gst_pad_set_caps(enc->srcpad, src_caps); gst_caps_unref(src_caps); return res; } gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps) { if (!gst_caps_is_fixed(caps)) { GST_DEBUG_OBJECT(enc, "didn't receive fixed caps, " "returning false"); return FALSE; } if (!gst_sbc_util_fill_sbc_params(&enc->sbc, caps)) return FALSE; if (enc->rate != 0 && gst_sbc_parse_rate_from_sbc(enc->sbc.frequency) != enc->rate) goto fail; if (enc->channels != 0 && gst_sbc_get_channel_number(enc->sbc.mode) != enc->channels) goto fail; if (enc->blocks != 0 && gst_sbc_parse_blocks_from_sbc(enc->sbc.blocks) != enc->blocks) goto fail; if (enc->subbands != 0 && gst_sbc_parse_subbands_from_sbc( enc->sbc.subbands) != enc->subbands) goto fail; if (enc->mode != SBC_ENC_DEFAULT_MODE && enc->sbc.mode != enc->mode) goto fail; if (enc->allocation != SBC_AM_AUTO && enc->sbc.allocation != enc->allocation) goto fail; if (enc->bitpool != SBC_ENC_BITPOOL_AUTO && enc->sbc.bitpool != enc->bitpool) goto fail; enc->codesize = sbc_get_codesize(&enc->sbc); enc->frame_length = sbc_get_frame_length(&enc->sbc); enc->frame_duration = sbc_get_frame_duration(&enc->sbc); GST_DEBUG_OBJECT(enc, "codesize: %d, frame_length: %d, frame_duration:" " %d", enc->codesize, enc->frame_length, enc->frame_duration); return TRUE; fail: memset(&enc->sbc, 0, sizeof(sbc_t)); return FALSE; } static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer) { GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad)); GstAdapter *adapter = enc->adapter; GstFlowReturn res = GST_FLOW_OK; gst_adapter_push(adapter, buffer); while (gst_adapter_available(adapter) >= enc->codesize && res == GST_FLOW_OK) { GstBuffer *output; GstCaps *caps; const guint8 *data; gint consumed; caps = GST_PAD_CAPS(enc->srcpad); res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad, GST_BUFFER_OFFSET_NONE, enc->frame_length, caps, &output); if (res != GST_FLOW_OK) goto done; data = gst_adapter_peek(adapter, enc->codesize); consumed = sbc_encode(&enc->sbc, (gpointer) data, enc->codesize, GST_BUFFER_DATA(output), GST_BUFFER_SIZE(output), NULL); if (consumed <= 0) { GST_DEBUG_OBJECT(enc, "comsumed < 0, codesize: %d", enc->codesize); break; } gst_adapter_flush(adapter, consumed); GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer); /* we have only 1 frame */ GST_BUFFER_DURATION(output) = enc->frame_duration; res = gst_pad_push(enc->srcpad, output); if (res != GST_FLOW_OK) goto done; } done: gst_object_unref(enc); return res; } static GstStateChangeReturn sbc_enc_change_state(GstElement *element, GstStateChange transition) { GstSbcEnc *enc = GST_SBC_ENC(element); switch (transition) { case GST_STATE_CHANGE_READY_TO_PAUSED: GST_DEBUG("Setup subband codec"); sbc_init(&enc->sbc, 0); break; case GST_STATE_CHANGE_PAUSED_TO_READY: GST_DEBUG("Finish subband codec"); sbc_finish(&enc->sbc); break; default: break; } return parent_class->change_state(element, transition); } static void gst_sbc_enc_dispose(GObject *object) { GstSbcEnc *enc = GST_SBC_ENC(object); if (enc->adapter != NULL) g_object_unref(G_OBJECT(enc->adapter)); enc->adapter = NULL; } static void gst_sbc_enc_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sbc_enc_sink_factory)); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&sbc_enc_src_factory)); gst_element_class_set_details(element_class, &sbc_enc_details); } static void gst_sbc_enc_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstSbcEnc *enc = GST_SBC_ENC(object); /* changes to those properties will only happen on the next caps * negotiation */ switch (prop_id) { case PROP_MODE: enc->mode = g_value_get_enum(value); break; case PROP_ALLOCATION: enc->allocation = g_value_get_enum(value); break; case PROP_BLOCKS: enc->blocks = g_value_get_enum(value); break; case PROP_SUBBANDS: enc->subbands = g_value_get_enum(value); break; case PROP_BITPOOL: enc->bitpool = g_value_get_int(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_sbc_enc_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstSbcEnc *enc = GST_SBC_ENC(object); switch (prop_id) { case PROP_MODE: g_value_set_enum(value, enc->mode); break; case PROP_ALLOCATION: g_value_set_enum(value, enc->allocation); break; case PROP_BLOCKS: g_value_set_enum(value, enc->blocks); break; case PROP_SUBBANDS: g_value_set_enum(value, enc->subbands); break; case PROP_BITPOOL: g_value_set_int(value, enc->bitpool); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_sbc_enc_class_init(GstSbcEncClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS(klass); GstElementClass *element_class = GST_ELEMENT_CLASS(klass); parent_class = g_type_class_peek_parent(klass); object_class->set_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_set_property); object_class->get_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_get_property); object_class->dispose = GST_DEBUG_FUNCPTR(gst_sbc_enc_dispose); element_class->change_state = GST_DEBUG_FUNCPTR(sbc_enc_change_state); g_object_class_install_property(object_class, PROP_MODE, g_param_spec_enum("mode", "Mode", "Encoding mode", GST_TYPE_SBC_MODE, SBC_ENC_DEFAULT_MODE, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_ALLOCATION, g_param_spec_enum("allocation", "Allocation", "Allocation method", GST_TYPE_SBC_ALLOCATION, SBC_ENC_DEFAULT_ALLOCATION, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_BLOCKS, g_param_spec_enum("blocks", "Blocks", "Blocks", GST_TYPE_SBC_BLOCKS, SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_SUBBANDS, g_param_spec_enum("subbands", "Sub bands", "Number of sub bands", GST_TYPE_SBC_SUBBANDS, SBC_ENC_DEFAULT_SUB_BANDS, G_PARAM_READWRITE)); g_object_class_install_property(object_class, PROP_BITPOOL, g_param_spec_int("bitpool", "Bitpool", "Bitpool (use 1 for automatic selection)", SBC_ENC_BITPOOL_AUTO, SBC_ENC_BITPOOL_MAX, SBC_ENC_BITPOOL_AUTO, G_PARAM_READWRITE)); GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0, "SBC encoding element"); } static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass) { self->sinkpad = gst_pad_new_from_static_template( &sbc_enc_sink_factory, "sink"); gst_pad_set_setcaps_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_sink_setcaps)); gst_element_add_pad(GST_ELEMENT(self), self->sinkpad); self->srcpad = gst_pad_new_from_static_template( &sbc_enc_src_factory, "src"); gst_pad_set_getcaps_function(self->srcpad, GST_DEBUG_FUNCPTR(sbc_enc_src_getcaps)); gst_pad_set_setcaps_function(self->srcpad, GST_DEBUG_FUNCPTR(sbc_enc_src_setcaps)); gst_element_add_pad(GST_ELEMENT(self), self->srcpad); gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(sbc_enc_chain)); self->subbands = SBC_ENC_DEFAULT_SUB_BANDS; self->blocks = SBC_ENC_DEFAULT_BLOCKS; self->mode = SBC_ENC_DEFAULT_MODE; self->allocation = SBC_ENC_DEFAULT_ALLOCATION; self->rate = SBC_ENC_DEFAULT_RATE; self->channels = SBC_ENC_DEFAULT_CHANNELS; self->bitpool = SBC_ENC_BITPOOL_AUTO; self->frame_length = 0; self->frame_duration = 0; self->adapter = gst_adapter_new(); } gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin) { return gst_element_register(plugin, "sbcenc", GST_RANK_NONE, GST_TYPE_SBC_ENC); } bluez-4.101/audio/device.h0000644000000000000000000000402111766125764012254 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ struct source; struct control; struct target; struct sink; struct headset; struct gateway; struct dev_priv; struct audio_device { struct btd_device *btd_dev; DBusConnection *conn; char *path; bdaddr_t src; bdaddr_t dst; gboolean auto_connect; struct headset *headset; struct gateway *gateway; struct sink *sink; struct source *source; struct control *control; struct target *target; guint hs_preauth_id; struct dev_priv *priv; }; struct audio_device *audio_device_register(DBusConnection *conn, struct btd_device *device, const char *path, const bdaddr_t *src, const bdaddr_t *dst); void audio_device_unregister(struct audio_device *device); gboolean audio_device_is_active(struct audio_device *dev, const char *interface); typedef void (*authorization_cb) (DBusError *derr, void *user_data); int audio_device_cancel_authorization(struct audio_device *dev, authorization_cb cb, void *user_data); int audio_device_request_authorization(struct audio_device *dev, const char *uuid, authorization_cb cb, void *user_data); void audio_device_set_authorized(struct audio_device *dev, gboolean auth); bluez-4.101/audio/main.c0000644000000000000000000001017311766125764011741 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "glib-helper.h" #include "btio.h" #include "plugin.h" #include "log.h" #include "device.h" #include "headset.h" #include "manager.h" #include "gateway.h" static GIOChannel *sco_server = NULL; static GKeyFile *load_config_file(const char *file) { GError *err = NULL; GKeyFile *keyfile; keyfile = g_key_file_new(); g_key_file_set_list_separator(keyfile, ','); if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { error("Parsing %s failed: %s", file, err->message); g_error_free(err); g_key_file_free(keyfile); return NULL; } return keyfile; } static void sco_server_cb(GIOChannel *chan, GError *err, gpointer data) { int sk; struct audio_device *device; char addr[18]; bdaddr_t src, dst; if (err) { error("sco_server_cb: %s", err->message); return; } bt_io_get(chan, BT_IO_SCO, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID); if (err) { error("bt_io_get: %s", err->message); goto drop; } device = manager_find_device(NULL, &src, &dst, AUDIO_HEADSET_INTERFACE, FALSE); if (!device) device = manager_find_device(NULL, &src, &dst, AUDIO_GATEWAY_INTERFACE, FALSE); if (!device) goto drop; if (device->headset) { if (headset_get_state(device) < HEADSET_STATE_CONNECTED) { DBG("Refusing SCO from non-connected headset"); goto drop; } if (!headset_get_hfp_active(device)) { error("Refusing non-HFP SCO connect attempt from %s", addr); goto drop; } if (headset_connect_sco(device, chan) < 0) goto drop; headset_set_state(device, HEADSET_STATE_PLAYING); } else if (device->gateway) { if (!gateway_is_connected(device)) { DBG("Refusing SCO from non-connected AG"); goto drop; } if (gateway_connect_sco(device, chan) < 0) goto drop; } else goto drop; sk = g_io_channel_unix_get_fd(chan); fcntl(sk, F_SETFL, 0); DBG("Accepted SCO connection from %s", addr); return; drop: g_io_channel_shutdown(chan, TRUE, NULL); } static DBusConnection *connection; static int audio_init(void) { GKeyFile *config; gboolean enable_sco; connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (connection == NULL) return -EIO; config = load_config_file(CONFIGDIR "/audio.conf"); if (audio_manager_init(connection, config, &enable_sco) < 0) goto failed; if (!enable_sco) return 0; sco_server = bt_io_listen(BT_IO_SCO, sco_server_cb, NULL, NULL, NULL, NULL, BT_IO_OPT_INVALID); if (!sco_server) { error("Unable to start SCO server socket"); goto failed; } return 0; failed: audio_manager_exit(); if (connection) { dbus_connection_unref(connection); connection = NULL; } return -EIO; } static void audio_exit(void) { if (sco_server) { g_io_channel_shutdown(sco_server, TRUE, NULL); g_io_channel_unref(sco_server); sco_server = NULL; } audio_manager_exit(); dbus_connection_unref(connection); } BLUETOOTH_PLUGIN_DEFINE(audio, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, audio_init, audio_exit) bluez-4.101/audio/avrcp.h0000644000000000000000000000716411766125764012143 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* player attributes */ #define AVRCP_ATTRIBUTE_ILEGAL 0x00 #define AVRCP_ATTRIBUTE_EQUALIZER 0x01 #define AVRCP_ATTRIBUTE_REPEAT_MODE 0x02 #define AVRCP_ATTRIBUTE_SHUFFLE 0x03 #define AVRCP_ATTRIBUTE_SCAN 0x04 /* equalizer values */ #define AVRCP_EQUALIZER_OFF 0x01 #define AVRCP_EQUALIZER_ON 0x02 /* repeat mode values */ #define AVRCP_REPEAT_MODE_OFF 0x01 #define AVRCP_REPEAT_MODE_SINGLE 0x02 #define AVRCP_REPEAT_MODE_ALL 0x03 #define AVRCP_REPEAT_MODE_GROUP 0x04 /* shuffle values */ #define AVRCP_SHUFFLE_OFF 0x01 #define AVRCP_SHUFFLE_ALL 0x02 #define AVRCP_SHUFFLE_GROUP 0x03 /* scan values */ #define AVRCP_SCAN_OFF 0x01 #define AVRCP_SCAN_ALL 0x02 #define AVRCP_SCAN_GROUP 0x03 /* media attributes */ #define AVRCP_MEDIA_ATTRIBUTE_ILLEGAL 0x00 #define AVRCP_MEDIA_ATTRIBUTE_TITLE 0x01 #define AVRCP_MEDIA_ATTRIBUTE_ARTIST 0x02 #define AVRCP_MEDIA_ATTRIBUTE_ALBUM 0x03 #define AVRCP_MEDIA_ATTRIBUTE_TRACK 0x04 #define AVRCP_MEDIA_ATTRIBUTE_N_TRACKS 0x05 #define AVRCP_MEDIA_ATTRIBUTE_GENRE 0x06 #define AVRCP_MEDIA_ATTRIBUTE_DURATION 0x07 #define AVRCP_MEDIA_ATTRIBUTE_LAST AVRCP_MEDIA_ATTRIBUTE_DURATION /* play status */ #define AVRCP_PLAY_STATUS_STOPPED 0x00 #define AVRCP_PLAY_STATUS_PLAYING 0x01 #define AVRCP_PLAY_STATUS_PAUSED 0x02 #define AVRCP_PLAY_STATUS_FWD_SEEK 0x03 #define AVRCP_PLAY_STATUS_REV_SEEK 0x04 #define AVRCP_PLAY_STATUS_ERROR 0xFF /* Notification events */ #define AVRCP_EVENT_STATUS_CHANGED 0x01 #define AVRCP_EVENT_TRACK_CHANGED 0x02 #define AVRCP_EVENT_TRACK_REACHED_END 0x03 #define AVRCP_EVENT_TRACK_REACHED_START 0x04 #define AVRCP_EVENT_VOLUME_CHANGED 0x0d #define AVRCP_EVENT_LAST AVRCP_EVENT_VOLUME_CHANGED struct avrcp_player_cb { int (*get_setting) (uint8_t attr, void *user_data); int (*set_setting) (uint8_t attr, uint8_t value, void *user_data); uint64_t (*get_uid) (void *user_data); void *(*get_metadata) (uint32_t id, void *user_data); GList *(*list_metadata) (void *user_data); uint8_t (*get_status) (void *user_data); uint32_t (*get_position) (void *user_data); void (*set_volume) (uint8_t volume, struct audio_device *dev, void *user_data); }; int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config); void avrcp_unregister(const bdaddr_t *src); gboolean avrcp_connect(struct audio_device *dev); void avrcp_disconnect(struct audio_device *dev); int avrcp_set_volume(struct audio_device *dev, uint8_t volume); struct avrcp_player *avrcp_register_player(const bdaddr_t *src, struct avrcp_player_cb *cb, void *user_data, GDestroyNotify destroy); void avrcp_unregister_player(struct avrcp_player *player); int avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data); size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands); bluez-4.101/audio/manager.h0000644000000000000000000000363411766125764012440 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ struct enabled_interfaces { gboolean hfp; gboolean headset; gboolean gateway; gboolean sink; gboolean source; gboolean control; gboolean socket; gboolean media; gboolean media_player; }; int audio_manager_init(DBusConnection *conn, GKeyFile *config, gboolean *enable_sco); void audio_manager_exit(void); gboolean server_is_enabled(bdaddr_t *src, uint16_t svc); struct audio_device *manager_find_device(const char *path, const bdaddr_t *src, const bdaddr_t *dst, const char *interface, gboolean connected); GSList *manager_find_devices(const char *path, const bdaddr_t *src, const bdaddr_t *dst, const char *interface, gboolean connected); struct audio_device *manager_get_device(const bdaddr_t *src, const bdaddr_t *dst, gboolean create); gboolean manager_allow_headset_connection(struct audio_device *device); /* TRUE to enable fast connectable and FALSE to disable fast connectable for all * audio adapters. */ void manager_set_fast_connectable(gboolean enable); bluez-4.101/audio/telephony-dummy.c0000644000000000000000000003010511766125764014152 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "log.h" #include "telephony.h" #include "error.h" #define TELEPHONY_DUMMY_IFACE "org.bluez.TelephonyTest" #define TELEPHONY_DUMMY_PATH "/org/bluez/test" static DBusConnection *connection = NULL; static const char *chld_str = "0,1,1x,2,2x,3,4"; static char *subscriber_number = NULL; static char *active_call_number = NULL; static int active_call_status = 0; static int active_call_dir = 0; static gboolean events_enabled = FALSE; static struct indicator dummy_indicators[] = { { "battchg", "0-5", 5, TRUE }, { "signal", "0-5", 5, TRUE }, { "service", "0,1", 1, TRUE }, { "call", "0,1", 0, TRUE }, { "callsetup", "0-3", 0, TRUE }, { "callheld", "0-2", 0, FALSE }, { "roam", "0,1", 0, TRUE }, { NULL } }; void telephony_device_connected(void *telephony_device) { DBG("telephony-dummy: device %p connected", telephony_device); } void telephony_device_disconnected(void *telephony_device) { DBG("telephony-dummy: device %p disconnected", telephony_device); events_enabled = FALSE; } void telephony_event_reporting_req(void *telephony_device, int ind) { events_enabled = ind == 1 ? TRUE : FALSE; telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE); } void telephony_response_and_hold_req(void *telephony_device, int rh) { telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED); } void telephony_last_dialed_number_req(void *telephony_device) { telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NONE); /* Notify outgoing call set-up successfully initiated */ telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_OUTGOING); telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_ALERTING); active_call_status = CALL_STATUS_ALERTING; active_call_dir = CALL_DIR_OUTGOING; } void telephony_terminate_call_req(void *telephony_device) { g_free(active_call_number); active_call_number = NULL; telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE); if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_INACTIVE); else telephony_update_indicator(dummy_indicators, "call", EV_CALL_INACTIVE); } void telephony_answer_call_req(void *telephony_device) { telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE); telephony_update_indicator(dummy_indicators, "call", EV_CALL_ACTIVE); telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_INACTIVE); active_call_status = CALL_STATUS_ACTIVE; } void telephony_dial_number_req(void *telephony_device, const char *number) { g_free(active_call_number); active_call_number = g_strdup(number); DBG("telephony-dummy: dial request to %s", active_call_number); telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE); /* Notify outgoing call set-up successfully initiated */ telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_OUTGOING); telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_ALERTING); active_call_status = CALL_STATUS_ALERTING; active_call_dir = CALL_DIR_OUTGOING; } void telephony_transmit_dtmf_req(void *telephony_device, char tone) { DBG("telephony-dummy: transmit dtmf: %c", tone); telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE); } void telephony_subscriber_number_req(void *telephony_device) { DBG("telephony-dummy: subscriber number request"); if (subscriber_number) telephony_subscriber_number_ind(subscriber_number, NUMBER_TYPE_TELEPHONY, SUBSCRIBER_SERVICE_VOICE); telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE); } void telephony_list_current_calls_req(void *telephony_device) { DBG("telephony-dummy: list current calls request"); if (active_call_number) telephony_list_current_call_ind(1, active_call_dir, active_call_status, CALL_MODE_VOICE, CALL_MULTIPARTY_NO, active_call_number, NUMBER_TYPE_TELEPHONY); telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE); } void telephony_operator_selection_req(void *telephony_device) { telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "DummyOperator"); telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE); } void telephony_call_hold_req(void *telephony_device, const char *cmd) { DBG("telephony-dymmy: got call hold request %s", cmd); telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE); } void telephony_nr_and_ec_req(void *telephony_device, gboolean enable) { DBG("telephony-dummy: got %s NR and EC request", enable ? "enable" : "disable"); telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE); } void telephony_voice_dial_req(void *telephony_device, gboolean enable) { DBG("telephony-dummy: got %s voice dial request", enable ? "enable" : "disable"); g_dbus_emit_signal(connection, TELEPHONY_DUMMY_PATH, TELEPHONY_DUMMY_IFACE, "VoiceDial", DBUS_TYPE_INVALID); telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE); } void telephony_key_press_req(void *telephony_device, const char *keys) { DBG("telephony-dummy: got key press request for %s", keys); telephony_key_press_rsp(telephony_device, CME_ERROR_NONE); } /* D-Bus method handlers */ static DBusMessage *outgoing_call(DBusConnection *conn, DBusMessage *msg, void *data) { const char *number; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); DBG("telephony-dummy: outgoing call to %s", number); g_free(active_call_number); active_call_number = g_strdup(number); telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_OUTGOING); telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_ALERTING); active_call_status = CALL_STATUS_ALERTING; active_call_dir = CALL_DIR_OUTGOING; return dbus_message_new_method_return(msg); } static DBusMessage *incoming_call(DBusConnection *conn, DBusMessage *msg, void *data) { const char *number; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); DBG("telephony-dummy: incoming call to %s", number); g_free(active_call_number); active_call_number = g_strdup(number); telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_INCOMING); active_call_status = CALL_STATUS_INCOMING; active_call_dir = CALL_DIR_INCOMING; telephony_incoming_call_ind(number, NUMBER_TYPE_TELEPHONY); return dbus_message_new_method_return(msg); } static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg, void *data) { DBG("telephony-dummy: cancel call"); g_free(active_call_number); active_call_number = NULL; if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) { telephony_update_indicator(dummy_indicators, "callsetup", EV_CALLSETUP_INACTIVE); telephony_calling_stopped_ind(); } if (telephony_get_indicator(dummy_indicators, "call") > 0) telephony_update_indicator(dummy_indicators, "call", EV_CALL_INACTIVE); return dbus_message_new_method_return(msg); } static DBusMessage *signal_strength(DBusConnection *conn, DBusMessage *msg, void *data) { dbus_uint32_t strength; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &strength, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); if (strength > 5) return btd_error_invalid_args(msg); telephony_update_indicator(dummy_indicators, "signal", strength); DBG("telephony-dummy: signal strength set to %u", strength); return dbus_message_new_method_return(msg); } static DBusMessage *battery_level(DBusConnection *conn, DBusMessage *msg, void *data) { dbus_uint32_t level; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &level, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); if (level > 5) return btd_error_invalid_args(msg); telephony_update_indicator(dummy_indicators, "battchg", level); DBG("telephony-dummy: battery level set to %u", level); return dbus_message_new_method_return(msg); } static DBusMessage *roaming_status(DBusConnection *conn, DBusMessage *msg, void *data) { dbus_bool_t roaming; int val; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &roaming, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); val = roaming ? EV_ROAM_ACTIVE : EV_ROAM_INACTIVE; telephony_update_indicator(dummy_indicators, "roam", val); DBG("telephony-dummy: roaming status set to %d", val); return dbus_message_new_method_return(msg); } static DBusMessage *registration_status(DBusConnection *conn, DBusMessage *msg, void *data) { dbus_bool_t registration; int val; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, ®istration, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); val = registration ? EV_SERVICE_PRESENT : EV_SERVICE_NONE; telephony_update_indicator(dummy_indicators, "service", val); DBG("telephony-dummy: registration status set to %d", val); return dbus_message_new_method_return(msg); } static DBusMessage *set_subscriber_number(DBusConnection *conn, DBusMessage *msg, void *data) { const char *number; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); g_free(subscriber_number); subscriber_number = g_strdup(number); DBG("telephony-dummy: subscriber number set to %s", number); return dbus_message_new_method_return(msg); } static const GDBusMethodTable dummy_methods[] = { { GDBUS_METHOD("OutgoingCall", GDBUS_ARGS({ "number", "s" }), NULL, outgoing_call) }, { GDBUS_METHOD("IncomingCall", GDBUS_ARGS({ "number", "s" }), NULL, incoming_call) }, { GDBUS_METHOD("CancelCall", NULL, NULL, cancel_call) }, { GDBUS_METHOD("SignalStrength", GDBUS_ARGS({ "strength", "u" }), NULL, signal_strength) }, { GDBUS_METHOD("BatteryLevel", GDBUS_ARGS({ "level", "u" }), NULL, battery_level) }, { GDBUS_METHOD("RoamingStatus", GDBUS_ARGS({ "roaming", "b" }), NULL, roaming_status) }, { GDBUS_METHOD("RegistrationStatus", GDBUS_ARGS({ "registration", "b" }), NULL, registration_status) }, { GDBUS_METHOD("SetSubscriberNumber", GDBUS_ARGS({ "number", "s" }), NULL, set_subscriber_number) }, { } }; static const GDBusSignalTable dummy_signals[] = { { GDBUS_SIGNAL("VoiceDial", NULL) }, { } }; int telephony_init(void) { uint32_t features = AG_FEATURE_REJECT_A_CALL | AG_FEATURE_ENHANCED_CALL_STATUS | AG_FEATURE_EXTENDED_ERROR_RESULT_CODES; DBG(""); connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (g_dbus_register_interface(connection, TELEPHONY_DUMMY_PATH, TELEPHONY_DUMMY_IFACE, dummy_methods, dummy_signals, NULL, NULL, NULL) == FALSE) { error("telephony-dummy interface %s init failed on path %s", TELEPHONY_DUMMY_IFACE, TELEPHONY_DUMMY_PATH); return -1; } telephony_ready_ind(features, dummy_indicators, BTRH_NOT_SUPPORTED, chld_str); return 0; } void telephony_exit(void) { DBG(""); g_dbus_unregister_interface(connection, TELEPHONY_DUMMY_PATH, TELEPHONY_DUMMY_IFACE); dbus_connection_unref(connection); connection = NULL; telephony_deinit(); } bluez-4.101/audio/avctp.c0000644000000000000000000006025611766125764012141 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2011 Texas Instruments, Inc. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "adapter.h" #include "../src/device.h" #include "log.h" #include "error.h" #include "uinput.h" #include "btio.h" #include "manager.h" #include "device.h" #include "avctp.h" #include "avrcp.h" #define QUIRK_NO_RELEASE 1 << 0 /* Message types */ #define AVCTP_COMMAND 0 #define AVCTP_RESPONSE 1 /* Packet types */ #define AVCTP_PACKET_SINGLE 0 #define AVCTP_PACKET_START 1 #define AVCTP_PACKET_CONTINUE 2 #define AVCTP_PACKET_END 3 #if __BYTE_ORDER == __LITTLE_ENDIAN struct avctp_header { uint8_t ipid:1; uint8_t cr:1; uint8_t packet_type:2; uint8_t transaction:4; uint16_t pid; } __attribute__ ((packed)); #define AVCTP_HEADER_LENGTH 3 struct avc_header { uint8_t code:4; uint8_t _hdr0:4; uint8_t subunit_id:3; uint8_t subunit_type:5; uint8_t opcode; } __attribute__ ((packed)); #elif __BYTE_ORDER == __BIG_ENDIAN struct avctp_header { uint8_t transaction:4; uint8_t packet_type:2; uint8_t cr:1; uint8_t ipid:1; uint16_t pid; } __attribute__ ((packed)); #define AVCTP_HEADER_LENGTH 3 struct avc_header { uint8_t _hdr0:4; uint8_t code:4; uint8_t subunit_type:5; uint8_t subunit_id:3; uint8_t opcode; } __attribute__ ((packed)); #else #error "Unknown byte order" #endif struct avctp_state_callback { avctp_state_cb cb; void *user_data; unsigned int id; }; struct avctp_server { bdaddr_t src; GIOChannel *io; GSList *sessions; }; struct avctp_rsp_handler { uint8_t id; avctp_rsp_cb func; void *user_data; }; struct avctp { struct avctp_server *server; bdaddr_t dst; avctp_state_t state; int uinput; GIOChannel *io; guint io_id; uint16_t mtu; uint8_t key_quirks[256]; GSList *handlers; }; struct avctp_pdu_handler { uint8_t opcode; avctp_pdu_cb cb; void *user_data; unsigned int id; }; static struct { const char *name; uint8_t avc; uint16_t uinput; } key_map[] = { { "PLAY", PLAY_OP, KEY_PLAYCD }, { "STOP", STAVC_OP_OP, KEY_STOPCD }, { "PAUSE", PAUSE_OP, KEY_PAUSECD }, { "FORWARD", FORWARD_OP, KEY_NEXTSONG }, { "BACKWARD", BACKWARD_OP, KEY_PREVIOUSSONG }, { "REWIND", REWIND_OP, KEY_REWIND }, { "FAST FORWARD", FAST_FORWARD_OP, KEY_FASTFORWARD }, { NULL } }; static GSList *callbacks = NULL; static GSList *servers = NULL; static GSList *handlers = NULL; static uint8_t id = 0; static void auth_cb(DBusError *derr, void *user_data); static int send_event(int fd, uint16_t type, uint16_t code, int32_t value) { struct uinput_event event; memset(&event, 0, sizeof(event)); event.type = type; event.code = code; event.value = value; return write(fd, &event, sizeof(event)); } static void send_key(int fd, uint16_t key, int pressed) { if (fd < 0) return; send_event(fd, EV_KEY, key, pressed); send_event(fd, EV_SYN, SYN_REPORT, 0); } static size_t handle_panel_passthrough(struct avctp *session, uint8_t transaction, uint8_t *code, uint8_t *subunit, uint8_t *operands, size_t operand_count, void *user_data) { const char *status; int pressed, i; if (*code != AVC_CTYPE_CONTROL || *subunit != AVC_SUBUNIT_PANEL) { *code = AVC_CTYPE_REJECTED; return 0; } if (operand_count == 0) goto done; if (operands[0] & 0x80) { status = "released"; pressed = 0; } else { status = "pressed"; pressed = 1; } for (i = 0; key_map[i].name != NULL; i++) { uint8_t key_quirks; if ((operands[0] & 0x7F) != key_map[i].avc) continue; DBG("AV/C: %s %s", key_map[i].name, status); key_quirks = session->key_quirks[key_map[i].avc]; if (key_quirks & QUIRK_NO_RELEASE) { if (!pressed) { DBG("AV/C: Ignoring release"); break; } DBG("AV/C: treating key press as press + release"); send_key(session->uinput, key_map[i].uinput, 1); send_key(session->uinput, key_map[i].uinput, 0); break; } send_key(session->uinput, key_map[i].uinput, pressed); break; } if (key_map[i].name == NULL) { DBG("AV/C: unknown button 0x%02X %s", operands[0] & 0x7F, status); *code = AVC_CTYPE_NOT_IMPLEMENTED; return 0; } done: *code = AVC_CTYPE_ACCEPTED; return operand_count; } static size_t handle_unit_info(struct avctp *session, uint8_t transaction, uint8_t *code, uint8_t *subunit, uint8_t *operands, size_t operand_count, void *user_data) { if (*code != AVC_CTYPE_STATUS) { *code = AVC_CTYPE_REJECTED; return 0; } *code = AVC_CTYPE_STABLE; /* The first operand should be 0x07 for the UNITINFO response. * Neither AVRCP (section 22.1, page 117) nor AVC Digital * Interface Command Set (section 9.2.1, page 45) specs * explain this value but both use it */ if (operand_count >= 1) operands[0] = 0x07; if (operand_count >= 2) operands[1] = AVC_SUBUNIT_PANEL << 3; DBG("reply to AVC_OP_UNITINFO"); return operand_count; } static size_t handle_subunit_info(struct avctp *session, uint8_t transaction, uint8_t *code, uint8_t *subunit, uint8_t *operands, size_t operand_count, void *user_data) { if (*code != AVC_CTYPE_STATUS) { *code = AVC_CTYPE_REJECTED; return 0; } *code = AVC_CTYPE_STABLE; /* The first operand should be 0x07 for the UNITINFO response. * Neither AVRCP (section 22.1, page 117) nor AVC Digital * Interface Command Set (section 9.2.1, page 45) specs * explain this value but both use it */ if (operand_count >= 2) operands[1] = AVC_SUBUNIT_PANEL << 3; DBG("reply to AVC_OP_SUBUNITINFO"); return operand_count; } static struct avctp_pdu_handler *find_handler(GSList *list, uint8_t opcode) { for (; list; list = list->next) { struct avctp_pdu_handler *handler = list->data; if (handler->opcode == opcode) return handler; } return NULL; } static void avctp_disconnected(struct avctp *session) { struct avctp_server *server; if (!session) return; if (session->io) { g_io_channel_shutdown(session->io, TRUE, NULL); g_io_channel_unref(session->io); session->io = NULL; } if (session->io_id) { g_source_remove(session->io_id); session->io_id = 0; if (session->state == AVCTP_STATE_CONNECTING) { struct audio_device *dev; dev = manager_get_device(&session->server->src, &session->dst, FALSE); audio_device_cancel_authorization(dev, auth_cb, session); } } if (session->uinput >= 0) { char address[18]; ba2str(&session->dst, address); DBG("AVCTP: closing uinput for %s", address); ioctl(session->uinput, UI_DEV_DESTROY); close(session->uinput); session->uinput = -1; } server = session->server; server->sessions = g_slist_remove(server->sessions, session); g_slist_free_full(session->handlers, g_free); g_free(session); } static void avctp_set_state(struct avctp *session, avctp_state_t new_state) { GSList *l; struct audio_device *dev; avctp_state_t old_state = session->state; dev = manager_get_device(&session->server->src, &session->dst, FALSE); if (dev == NULL) { error("avdtp_set_state(): no matching audio device"); return; } session->state = new_state; for (l = callbacks; l != NULL; l = l->next) { struct avctp_state_callback *cb = l->data; cb->cb(dev, old_state, new_state, cb->user_data); } switch (new_state) { case AVCTP_STATE_DISCONNECTED: DBG("AVCTP Disconnected"); avctp_disconnected(session); if (old_state != AVCTP_STATE_CONNECTED) break; if (!audio_device_is_active(dev, NULL)) audio_device_set_authorized(dev, FALSE); break; case AVCTP_STATE_CONNECTING: DBG("AVCTP Connecting"); break; case AVCTP_STATE_CONNECTED: DBG("AVCTP Connected"); break; default: error("Invalid AVCTP state %d", new_state); return; } } static void handle_response(struct avctp *session, struct avctp_header *avctp, struct avc_header *avc, uint8_t *operands, size_t operand_count) { GSList *l; for (l = session->handlers; l; l = l->next) { struct avctp_rsp_handler *handler = l->data; if (handler->id != avctp->transaction) continue; if (handler->func && handler->func(session, avc->code, avc->subunit_type, operands, operand_count, handler->user_data)) return; session->handlers = g_slist_remove(session->handlers, handler); g_free(handler); return; } } static gboolean session_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct avctp *session = data; uint8_t buf[1024], *operands, code, subunit; struct avctp_header *avctp; struct avc_header *avc; int ret, packet_size, operand_count, sock; struct avctp_pdu_handler *handler; if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) goto failed; sock = g_io_channel_unix_get_fd(session->io); ret = read(sock, buf, sizeof(buf)); if (ret <= 0) goto failed; DBG("Got %d bytes of data for AVCTP session %p", ret, session); if ((unsigned int) ret < sizeof(struct avctp_header)) { error("Too small AVCTP packet"); goto failed; } avctp = (struct avctp_header *) buf; DBG("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, " "PID 0x%04X", avctp->transaction, avctp->packet_type, avctp->cr, avctp->ipid, ntohs(avctp->pid)); ret -= sizeof(struct avctp_header); if ((unsigned int) ret < sizeof(struct avc_header)) { error("Too small AVCTP packet"); goto failed; } avc = (struct avc_header *) (buf + sizeof(struct avctp_header)); ret -= sizeof(struct avc_header); operands = buf + sizeof(struct avctp_header) + sizeof(struct avc_header); operand_count = ret; DBG("AV/C %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, " "opcode 0x%02X, %d operands", avctp->cr ? "response" : "command", avc->code, avc->subunit_type, avc->subunit_id, avc->opcode, operand_count); if (avctp->cr == AVCTP_RESPONSE) { handle_response(session, avctp, avc, operands, operand_count); return TRUE; } packet_size = AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH; avctp->cr = AVCTP_RESPONSE; if (avctp->packet_type != AVCTP_PACKET_SINGLE) { avc->code = AVC_CTYPE_NOT_IMPLEMENTED; goto done; } if (avctp->pid != htons(AV_REMOTE_SVCLASS_ID)) { avctp->ipid = 1; avc->code = AVC_CTYPE_REJECTED; goto done; } handler = find_handler(handlers, avc->opcode); if (!handler) { DBG("handler not found for 0x%02x", avc->opcode); packet_size += avrcp_handle_vendor_reject(&code, operands); avc->code = code; goto done; } code = avc->code; subunit = avc->subunit_type; packet_size += handler->cb(session, avctp->transaction, &code, &subunit, operands, operand_count, handler->user_data); avc->code = code; avc->subunit_type = subunit; done: ret = write(sock, buf, packet_size); if (ret != packet_size) goto failed; return TRUE; failed: DBG("AVCTP session %p got disconnected", session); avctp_set_state(session, AVCTP_STATE_DISCONNECTED); return FALSE; } static int uinput_create(char *name) { struct uinput_dev dev; int fd, err, i; fd = open("/dev/uinput", O_RDWR); if (fd < 0) { fd = open("/dev/input/uinput", O_RDWR); if (fd < 0) { fd = open("/dev/misc/uinput", O_RDWR); if (fd < 0) { err = -errno; error("Can't open input device: %s (%d)", strerror(-err), -err); return err; } } } memset(&dev, 0, sizeof(dev)); if (name) strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1); dev.id.bustype = BUS_BLUETOOTH; dev.id.vendor = 0x0000; dev.id.product = 0x0000; dev.id.version = 0x0000; if (write(fd, &dev, sizeof(dev)) < 0) { err = -errno; error("Can't write device information: %s (%d)", strerror(-err), -err); close(fd); return err; } ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_REL); ioctl(fd, UI_SET_EVBIT, EV_REP); ioctl(fd, UI_SET_EVBIT, EV_SYN); for (i = 0; key_map[i].name != NULL; i++) ioctl(fd, UI_SET_KEYBIT, key_map[i].uinput); if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) { err = -errno; error("Can't create uinput device: %s (%d)", strerror(-err), -err); close(fd); return err; } return fd; } static void init_uinput(struct avctp *session) { struct audio_device *dev; char address[18], name[248 + 1]; dev = manager_get_device(&session->server->src, &session->dst, FALSE); device_get_name(dev->btd_dev, name, sizeof(name)); if (g_str_equal(name, "Nokia CK-20W")) { session->key_quirks[FORWARD_OP] |= QUIRK_NO_RELEASE; session->key_quirks[BACKWARD_OP] |= QUIRK_NO_RELEASE; session->key_quirks[PLAY_OP] |= QUIRK_NO_RELEASE; session->key_quirks[PAUSE_OP] |= QUIRK_NO_RELEASE; } ba2str(&session->dst, address); session->uinput = uinput_create(address); if (session->uinput < 0) error("AVRCP: failed to init uinput for %s", address); else DBG("AVRCP: uinput initialized for %s", address); } static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data) { struct avctp *session = data; char address[18]; uint16_t imtu; GError *gerr = NULL; if (err) { avctp_set_state(session, AVCTP_STATE_DISCONNECTED); error("%s", err->message); return; } bt_io_get(chan, BT_IO_L2CAP, &gerr, BT_IO_OPT_DEST, &address, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID); if (gerr) { avctp_set_state(session, AVCTP_STATE_DISCONNECTED); error("%s", gerr->message); g_error_free(gerr); return; } DBG("AVCTP: connected to %s", address); if (!session->io) session->io = g_io_channel_ref(chan); init_uinput(session); avctp_set_state(session, AVCTP_STATE_CONNECTED); session->mtu = imtu; session->io_id = g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) session_cb, session); } static void auth_cb(DBusError *derr, void *user_data) { struct avctp *session = user_data; GError *err = NULL; if (session->io_id) { g_source_remove(session->io_id); session->io_id = 0; } if (derr && dbus_error_is_set(derr)) { error("Access denied: %s", derr->message); avctp_set_state(session, AVCTP_STATE_DISCONNECTED); return; } if (!bt_io_accept(session->io, avctp_connect_cb, session, NULL, &err)) { error("bt_io_accept: %s", err->message); g_error_free(err); avctp_set_state(session, AVCTP_STATE_DISCONNECTED); } } static struct avctp_server *find_server(GSList *list, const bdaddr_t *src) { for (; list; list = list->next) { struct avctp_server *server = list->data; if (bacmp(&server->src, src) == 0) return server; } return NULL; } static struct avctp *find_session(GSList *list, const bdaddr_t *dst) { for (; list != NULL; list = g_slist_next(list)) { struct avctp *s = list->data; if (bacmp(dst, &s->dst)) continue; return s; } return NULL; } static struct avctp *avctp_get_internal(const bdaddr_t *src, const bdaddr_t *dst) { struct avctp_server *server; struct avctp *session; assert(src != NULL); assert(dst != NULL); server = find_server(servers, src); if (server == NULL) return NULL; session = find_session(server->sessions, dst); if (session) return session; session = g_new0(struct avctp, 1); session->server = server; bacpy(&session->dst, dst); session->state = AVCTP_STATE_DISCONNECTED; server->sessions = g_slist_append(server->sessions, session); return session; } static void avctp_confirm_cb(GIOChannel *chan, gpointer data) { struct avctp *session; struct audio_device *dev; char address[18]; bdaddr_t src, dst; GError *err = NULL; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); g_io_channel_shutdown(chan, TRUE, NULL); return; } DBG("AVCTP: incoming connect from %s", address); session = avctp_get_internal(&src, &dst); if (!session) goto drop; dev = manager_get_device(&src, &dst, FALSE); if (!dev) { dev = manager_get_device(&src, &dst, TRUE); if (!dev) { error("Unable to get audio device object for %s", address); goto drop; } } if (dev->control == NULL) { btd_device_add_uuid(dev->btd_dev, AVRCP_REMOTE_UUID); if (dev->control == NULL) goto drop; } if (session->io) { error("Refusing unexpected connect from %s", address); goto drop; } avctp_set_state(session, AVCTP_STATE_CONNECTING); session->io = g_io_channel_ref(chan); if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID, auth_cb, session) < 0) goto drop; session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, session_cb, session); return; drop: if (!session || !session->io) g_io_channel_shutdown(chan, TRUE, NULL); if (session) avctp_set_state(session, AVCTP_STATE_DISCONNECTED); } static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master) { GError *err = NULL; GIOChannel *io; io = bt_io_listen(BT_IO_L2CAP, NULL, avctp_confirm_cb, NULL, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_PSM, AVCTP_PSM, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_MASTER, master, BT_IO_OPT_INVALID); if (!io) { error("%s", err->message); g_error_free(err); } return io; } static unsigned int passthrough_id = 0; static unsigned int unit_id = 0; static unsigned int subunit_id = 0; int avctp_register(const bdaddr_t *src, gboolean master) { struct avctp_server *server; server = g_new0(struct avctp_server, 1); if (!server) return -ENOMEM; server->io = avctp_server_socket(src, master); if (!server->io) { g_free(server); return -1; } bacpy(&server->src, src); servers = g_slist_append(servers, server); if (!passthrough_id) passthrough_id = avctp_register_pdu_handler(AVC_OP_PASSTHROUGH, handle_panel_passthrough, NULL); if (!unit_id) unit_id = avctp_register_pdu_handler(AVC_OP_UNITINFO, handle_unit_info, NULL); if (!subunit_id) subunit_id = avctp_register_pdu_handler(AVC_OP_SUBUNITINFO, handle_subunit_info, NULL); return 0; } void avctp_unregister(const bdaddr_t *src) { struct avctp_server *server; server = find_server(servers, src); if (!server) return; while (server->sessions) avctp_disconnected(server->sessions->data); servers = g_slist_remove(servers, server); g_io_channel_shutdown(server->io, TRUE, NULL); g_io_channel_unref(server->io); g_free(server); if (servers) return; if (passthrough_id) { avctp_unregister_pdu_handler(passthrough_id); passthrough_id = 0; } if (unit_id) { avctp_unregister_pdu_handler(unit_id); passthrough_id = 0; } if (subunit_id) { avctp_unregister_pdu_handler(subunit_id); subunit_id = 0; } } int avctp_send_passthrough(struct avctp *session, uint8_t op) { unsigned char buf[AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH + 2]; struct avctp_header *avctp = (void *) buf; struct avc_header *avc = (void *) &buf[AVCTP_HEADER_LENGTH]; uint8_t *operands = &buf[AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH]; int sk; if (session->state != AVCTP_STATE_CONNECTED) return -ENOTCONN; memset(buf, 0, sizeof(buf)); avctp->transaction = id++; avctp->packet_type = AVCTP_PACKET_SINGLE; avctp->cr = AVCTP_COMMAND; avctp->pid = htons(AV_REMOTE_SVCLASS_ID); avc->code = AVC_CTYPE_CONTROL; avc->subunit_type = AVC_SUBUNIT_PANEL; avc->opcode = AVC_OP_PASSTHROUGH; operands[0] = op & 0x7f; operands[1] = 0; sk = g_io_channel_unix_get_fd(session->io); if (write(sk, buf, sizeof(buf)) < 0) return -errno; /* Button release */ avctp->transaction = id++; operands[0] |= 0x80; if (write(sk, buf, sizeof(buf)) < 0) return -errno; return 0; } static int avctp_send(struct avctp *session, uint8_t transaction, uint8_t cr, uint8_t code, uint8_t subunit, uint8_t opcode, uint8_t *operands, size_t operand_count) { uint8_t *buf; struct avctp_header *avctp; struct avc_header *avc; uint8_t *pdu; int sk, err = 0; uint16_t size; if (session->state != AVCTP_STATE_CONNECTED) return -ENOTCONN; sk = g_io_channel_unix_get_fd(session->io); size = AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH + operand_count; buf = g_malloc0(size); avctp = (void *) buf; avc = (void *) &buf[AVCTP_HEADER_LENGTH]; pdu = (void *) &buf[AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH]; avctp->transaction = transaction; avctp->packet_type = AVCTP_PACKET_SINGLE; avctp->cr = cr; avctp->pid = htons(AV_REMOTE_SVCLASS_ID); avc->code = code; avc->subunit_type = subunit; avc->opcode = opcode; memcpy(pdu, operands, operand_count); if (write(sk, buf, size) < 0) err = -errno; g_free(buf); return err; } int avctp_send_vendordep(struct avctp *session, uint8_t transaction, uint8_t code, uint8_t subunit, uint8_t *operands, size_t operand_count) { return avctp_send(session, transaction, AVCTP_RESPONSE, code, subunit, AVC_OP_VENDORDEP, operands, operand_count); } int avctp_send_vendordep_req(struct avctp *session, uint8_t code, uint8_t subunit, uint8_t *operands, size_t operand_count, avctp_rsp_cb func, void *user_data) { struct avctp_rsp_handler *handler; int err; err = avctp_send(session, id, AVCTP_COMMAND, code, subunit, AVC_OP_VENDORDEP, operands, operand_count); if (err < 0) return err; handler = g_new0(struct avctp_rsp_handler, 1); handler->id = id; handler->func = func; handler->user_data = user_data; session->handlers = g_slist_prepend(session->handlers, handler); id++; return 0; } unsigned int avctp_add_state_cb(avctp_state_cb cb, void *user_data) { struct avctp_state_callback *state_cb; static unsigned int id = 0; state_cb = g_new(struct avctp_state_callback, 1); state_cb->cb = cb; state_cb->user_data = user_data; state_cb->id = ++id; callbacks = g_slist_append(callbacks, state_cb); return state_cb->id; } gboolean avctp_remove_state_cb(unsigned int id) { GSList *l; for (l = callbacks; l != NULL; l = l->next) { struct avctp_state_callback *cb = l->data; if (cb && cb->id == id) { callbacks = g_slist_remove(callbacks, cb); g_free(cb); return TRUE; } } return FALSE; } unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_pdu_cb cb, void *user_data) { struct avctp_pdu_handler *handler; static unsigned int id = 0; handler = find_handler(handlers, opcode); if (handler) return 0; handler = g_new(struct avctp_pdu_handler, 1); handler->opcode = opcode; handler->cb = cb; handler->user_data = user_data; handler->id = ++id; handlers = g_slist_append(handlers, handler); return handler->id; } gboolean avctp_unregister_pdu_handler(unsigned int id) { GSList *l; for (l = handlers; l != NULL; l = l->next) { struct avctp_pdu_handler *handler = l->data; if (handler->id == id) { handlers = g_slist_remove(handlers, handler); g_free(handler); return TRUE; } } return FALSE; } struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst) { struct avctp *session; GError *err = NULL; GIOChannel *io; session = avctp_get_internal(src, dst); if (!session) return NULL; if (session->state > AVCTP_STATE_DISCONNECTED) return session; avctp_set_state(session, AVCTP_STATE_CONNECTING); io = bt_io_connect(BT_IO_L2CAP, avctp_connect_cb, session, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &session->server->src, BT_IO_OPT_DEST_BDADDR, &session->dst, BT_IO_OPT_PSM, AVCTP_PSM, BT_IO_OPT_INVALID); if (err) { avctp_set_state(session, AVCTP_STATE_DISCONNECTED); error("%s", err->message); g_error_free(err); return NULL; } session->io = io; return session; } void avctp_disconnect(struct avctp *session) { if (!session->io) return; avctp_set_state(session, AVCTP_STATE_DISCONNECTED); } struct avctp *avctp_get(const bdaddr_t *src, const bdaddr_t *dst) { return avctp_get_internal(src, dst); } bluez-4.101/audio/rtp.h0000644000000000000000000000342511376221745011622 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #if __BYTE_ORDER == __LITTLE_ENDIAN struct rtp_header { unsigned cc:4; unsigned x:1; unsigned p:1; unsigned v:2; unsigned pt:7; unsigned m:1; uint16_t sequence_number; uint32_t timestamp; uint32_t ssrc; uint32_t csrc[0]; } __attribute__ ((packed)); struct rtp_payload { unsigned frame_count:4; unsigned rfa0:1; unsigned is_last_fragment:1; unsigned is_first_fragment:1; unsigned is_fragmented:1; } __attribute__ ((packed)); #elif __BYTE_ORDER == __BIG_ENDIAN struct rtp_header { unsigned v:2; unsigned p:1; unsigned x:1; unsigned cc:4; unsigned m:1; unsigned pt:7; uint16_t sequence_number; uint32_t timestamp; uint32_t ssrc; uint32_t csrc[0]; } __attribute__ ((packed)); struct rtp_payload { unsigned is_fragmented:1; unsigned is_first_fragment:1; unsigned is_last_fragment:1; unsigned rfa0:1; unsigned frame_count:4; } __attribute__ ((packed)); #else #error "Unknown byte order" #endif bluez-4.101/audio/gstsbcenc.h0000644000000000000000000000360011571052274012757 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "sbc.h" G_BEGIN_DECLS #define GST_TYPE_SBC_ENC \ (gst_sbc_enc_get_type()) #define GST_SBC_ENC(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_ENC,GstSbcEnc)) #define GST_SBC_ENC_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_ENC,GstSbcEncClass)) #define GST_IS_SBC_ENC(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_ENC)) #define GST_IS_SBC_ENC_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_ENC)) typedef struct _GstSbcEnc GstSbcEnc; typedef struct _GstSbcEncClass GstSbcEncClass; struct _GstSbcEnc { GstElement element; GstPad *sinkpad; GstPad *srcpad; GstAdapter *adapter; gint rate; gint channels; gint mode; gint blocks; gint allocation; gint subbands; gint bitpool; guint codesize; gint frame_length; gint frame_duration; sbc_t sbc; }; struct _GstSbcEncClass { GstElementClass parent_class; }; GType gst_sbc_enc_get_type(void); gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin); G_END_DECLS bluez-4.101/audio/a2dp-codecs.h0000644000000000000000000000614411766125764013111 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define A2DP_CODEC_SBC 0x00 #define A2DP_CODEC_MPEG12 0x01 #define A2DP_CODEC_MPEG24 0x02 #define A2DP_CODEC_ATRAC 0x03 #define SBC_SAMPLING_FREQ_16000 (1 << 3) #define SBC_SAMPLING_FREQ_32000 (1 << 2) #define SBC_SAMPLING_FREQ_44100 (1 << 1) #define SBC_SAMPLING_FREQ_48000 1 #define SBC_CHANNEL_MODE_MONO (1 << 3) #define SBC_CHANNEL_MODE_DUAL_CHANNEL (1 << 2) #define SBC_CHANNEL_MODE_STEREO (1 << 1) #define SBC_CHANNEL_MODE_JOINT_STEREO 1 #define SBC_BLOCK_LENGTH_4 (1 << 3) #define SBC_BLOCK_LENGTH_8 (1 << 2) #define SBC_BLOCK_LENGTH_12 (1 << 1) #define SBC_BLOCK_LENGTH_16 1 #define SBC_SUBBANDS_4 (1 << 1) #define SBC_SUBBANDS_8 1 #define SBC_ALLOCATION_SNR (1 << 1) #define SBC_ALLOCATION_LOUDNESS 1 #define MPEG_CHANNEL_MODE_MONO (1 << 3) #define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2) #define MPEG_CHANNEL_MODE_STEREO (1 << 1) #define MPEG_CHANNEL_MODE_JOINT_STEREO 1 #define MPEG_LAYER_MP1 (1 << 2) #define MPEG_LAYER_MP2 (1 << 1) #define MPEG_LAYER_MP3 1 #define MPEG_SAMPLING_FREQ_16000 (1 << 5) #define MPEG_SAMPLING_FREQ_22050 (1 << 4) #define MPEG_SAMPLING_FREQ_24000 (1 << 3) #define MPEG_SAMPLING_FREQ_32000 (1 << 2) #define MPEG_SAMPLING_FREQ_44100 (1 << 1) #define MPEG_SAMPLING_FREQ_48000 1 #define MAX_BITPOOL 64 #define MIN_BITPOOL 2 #if __BYTE_ORDER == __LITTLE_ENDIAN typedef struct { uint8_t channel_mode:4; uint8_t frequency:4; uint8_t allocation_method:2; uint8_t subbands:2; uint8_t block_length:4; uint8_t min_bitpool; uint8_t max_bitpool; } __attribute__ ((packed)) a2dp_sbc_t; typedef struct { uint8_t channel_mode:4; uint8_t crc:1; uint8_t layer:3; uint8_t frequency:6; uint8_t mpf:1; uint8_t rfa:1; uint16_t bitrate; } __attribute__ ((packed)) a2dp_mpeg_t; #elif __BYTE_ORDER == __BIG_ENDIAN typedef struct { uint8_t frequency:4; uint8_t channel_mode:4; uint8_t block_length:4; uint8_t subbands:2; uint8_t allocation_method:2; uint8_t min_bitpool; uint8_t max_bitpool; } __attribute__ ((packed)) a2dp_sbc_t; typedef struct { uint8_t layer:3; uint8_t crc:1; uint8_t channel_mode:4; uint8_t rfa:1; uint8_t mpf:1; uint8_t frequency:6; uint16_t bitrate; } __attribute__ ((packed)) a2dp_mpeg_t; #else #error "Unknown byte order" #endif bluez-4.101/audio/avrcp.c0000644000000000000000000010343711766125764012136 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2011 Texas Instruments, Inc. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "../src/adapter.h" #include "../src/device.h" #include "log.h" #include "error.h" #include "device.h" #include "manager.h" #include "avctp.h" #include "avrcp.h" #include "sdpd.h" #include "dbus-common.h" /* Company IDs for vendor dependent commands */ #define IEEEID_BTSIG 0x001958 /* Error codes for metadata transfer */ #define E_INVALID_COMMAND 0x00 #define E_INVALID_PARAM 0x01 #define E_PARAM_NOT_FOUND 0x02 #define E_INTERNAL 0x03 /* Packet types */ #define AVRCP_PACKET_TYPE_SINGLE 0x00 #define AVRCP_PACKET_TYPE_START 0x01 #define AVRCP_PACKET_TYPE_CONTINUING 0x02 #define AVRCP_PACKET_TYPE_END 0x03 /* PDU types for metadata transfer */ #define AVRCP_GET_CAPABILITIES 0x10 #define AVRCP_LIST_PLAYER_ATTRIBUTES 0X11 #define AVRCP_LIST_PLAYER_VALUES 0x12 #define AVRCP_GET_CURRENT_PLAYER_VALUE 0x13 #define AVRCP_SET_PLAYER_VALUE 0x14 #define AVRCP_GET_PLAYER_ATTRIBUTE_TEXT 0x15 #define AVRCP_GET_PLAYER_VALUE_TEXT 0x16 #define AVRCP_DISPLAYABLE_CHARSET 0x17 #define AVRCP_CT_BATTERY_STATUS 0x18 #define AVRCP_GET_ELEMENT_ATTRIBUTES 0x20 #define AVRCP_GET_PLAY_STATUS 0x30 #define AVRCP_REGISTER_NOTIFICATION 0x31 #define AVRCP_REQUEST_CONTINUING 0x40 #define AVRCP_ABORT_CONTINUING 0x41 #define AVRCP_SET_ABSOLUTE_VOLUME 0x50 /* Capabilities for AVRCP_GET_CAPABILITIES pdu */ #define CAP_COMPANY_ID 0x02 #define CAP_EVENTS_SUPPORTED 0x03 #define AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH 5 #define AVRCP_FEATURE_CATEGORY_1 0x0001 #define AVRCP_FEATURE_CATEGORY_2 0x0002 #define AVRCP_FEATURE_CATEGORY_3 0x0004 #define AVRCP_FEATURE_CATEGORY_4 0x0008 #define AVRCP_FEATURE_PLAYER_SETTINGS 0x0010 enum battery_status { BATTERY_STATUS_NORMAL = 0, BATTERY_STATUS_WARNING = 1, BATTERY_STATUS_CRITICAL = 2, BATTERY_STATUS_EXTERNAL = 3, BATTERY_STATUS_FULL_CHARGE = 4, }; #if __BYTE_ORDER == __LITTLE_ENDIAN struct avrcp_header { uint8_t company_id[3]; uint8_t pdu_id; uint8_t packet_type:2; uint8_t rsvd:6; uint16_t params_len; uint8_t params[0]; } __attribute__ ((packed)); #define AVRCP_HEADER_LENGTH 7 #elif __BYTE_ORDER == __BIG_ENDIAN struct avrcp_header { uint8_t company_id[3]; uint8_t pdu_id; uint8_t rsvd:6; uint8_t packet_type:2; uint16_t params_len; uint8_t params[0]; } __attribute__ ((packed)); #define AVRCP_HEADER_LENGTH 7 #else #error "Unknown byte order" #endif #define AVRCP_MTU (AVC_MTU - AVC_HEADER_LENGTH) #define AVRCP_PDU_MTU (AVRCP_MTU - AVRCP_HEADER_LENGTH) struct avrcp_server { bdaddr_t src; uint32_t tg_record_id; uint32_t ct_record_id; GSList *players; struct avrcp_player *active_player; }; struct pending_pdu { uint8_t pdu_id; GList *attr_ids; uint16_t offset; }; struct avrcp_player { struct avrcp_server *server; struct avctp *session; struct audio_device *dev; unsigned int handler; uint16_t registered_events; uint8_t transaction_events[AVRCP_EVENT_LAST + 1]; struct pending_pdu *pending_pdu; struct avrcp_player_cb *cb; void *user_data; GDestroyNotify destroy; }; static GSList *servers = NULL; static unsigned int avctp_id = 0; /* Company IDs supported by this device */ static uint32_t company_ids[] = { IEEEID_BTSIG, }; static void register_volume_notification(struct avrcp_player *player); static sdp_record_t *avrcp_ct_record(void) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, l2cap, avctp, avrct; sdp_profile_desc_t profile[1]; sdp_list_t *aproto, *proto[2]; sdp_record_t *record; sdp_data_t *psm, *version, *features; uint16_t lp = AVCTP_PSM; uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103; uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 | AVRCP_FEATURE_CATEGORY_2 | AVRCP_FEATURE_CATEGORY_3 | AVRCP_FEATURE_CATEGORY_4 ); record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(record, root); /* Service Class ID List */ sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID); svclass_id = sdp_list_append(0, &avrct); sdp_set_service_classes(record, svclass_id); /* Protocol Descriptor List */ sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap); psm = sdp_data_alloc(SDP_UINT16, &lp); proto[0] = sdp_list_append(proto[0], psm); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&avctp, AVCTP_UUID); proto[1] = sdp_list_append(0, &avctp); version = sdp_data_alloc(SDP_UINT16, &avctp_ver); proto[1] = sdp_list_append(proto[1], version); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(record, aproto); /* Bluetooth Profile Descriptor List */ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID); profile[0].version = avrcp_ver; pfseq = sdp_list_append(0, &profile[0]); sdp_set_profile_descs(record, pfseq); features = sdp_data_alloc(SDP_UINT16, &feat); sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features); sdp_set_info_attr(record, "AVRCP CT", 0, 0); free(psm); free(version); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(pfseq, 0); sdp_list_free(aproto, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); return record; } static sdp_record_t *avrcp_tg_record(void) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, l2cap, avctp, avrtg; sdp_profile_desc_t profile[1]; sdp_list_t *aproto, *proto[2]; sdp_record_t *record; sdp_data_t *psm, *version, *features; uint16_t lp = AVCTP_PSM; uint16_t avrcp_ver = 0x0104, avctp_ver = 0x0103; uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 | AVRCP_FEATURE_CATEGORY_2 | AVRCP_FEATURE_CATEGORY_3 | AVRCP_FEATURE_CATEGORY_4 | AVRCP_FEATURE_PLAYER_SETTINGS ); record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(record, root); /* Service Class ID List */ sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID); svclass_id = sdp_list_append(0, &avrtg); sdp_set_service_classes(record, svclass_id); /* Protocol Descriptor List */ sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap); psm = sdp_data_alloc(SDP_UINT16, &lp); proto[0] = sdp_list_append(proto[0], psm); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&avctp, AVCTP_UUID); proto[1] = sdp_list_append(0, &avctp); version = sdp_data_alloc(SDP_UINT16, &avctp_ver); proto[1] = sdp_list_append(proto[1], version); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(record, aproto); /* Bluetooth Profile Descriptor List */ sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID); profile[0].version = avrcp_ver; pfseq = sdp_list_append(0, &profile[0]); sdp_set_profile_descs(record, pfseq); features = sdp_data_alloc(SDP_UINT16, &feat); sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features); sdp_set_info_attr(record, "AVRCP TG", 0, 0); free(psm); free(version); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(aproto, 0); sdp_list_free(pfseq, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); return record; } static unsigned int attr_get_max_val(uint8_t attr) { switch (attr) { case AVRCP_ATTRIBUTE_EQUALIZER: return AVRCP_EQUALIZER_ON; case AVRCP_ATTRIBUTE_REPEAT_MODE: return AVRCP_REPEAT_MODE_GROUP; case AVRCP_ATTRIBUTE_SHUFFLE: return AVRCP_SHUFFLE_GROUP; case AVRCP_ATTRIBUTE_SCAN: return AVRCP_SCAN_GROUP; } return 0; } static const char *battery_status_to_str(enum battery_status status) { switch (status) { case BATTERY_STATUS_NORMAL: return "normal"; case BATTERY_STATUS_WARNING: return "warning"; case BATTERY_STATUS_CRITICAL: return "critical"; case BATTERY_STATUS_EXTERNAL: return "external"; case BATTERY_STATUS_FULL_CHARGE: return "fullcharge"; } return NULL; } /* * get_company_id: * * Get three-byte Company_ID from incoming AVRCP message */ static uint32_t get_company_id(const uint8_t cid[3]) { return cid[0] << 16 | cid[1] << 8 | cid[2]; } /* * set_company_id: * * Set three-byte Company_ID into outgoing AVRCP message */ static void set_company_id(uint8_t cid[3], const uint32_t cid_in) { cid[0] = cid_in >> 16; cid[1] = cid_in >> 8; cid[2] = cid_in; } int avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data) { uint8_t buf[AVRCP_HEADER_LENGTH + 9]; struct avrcp_header *pdu = (void *) buf; uint16_t size; int err; if (player->session == NULL) return -ENOTCONN; if (!(player->registered_events & (1 << id))) return 0; memset(buf, 0, sizeof(buf)); set_company_id(pdu->company_id, IEEEID_BTSIG); pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION; pdu->params[0] = id; DBG("id=%u", id); switch (id) { case AVRCP_EVENT_STATUS_CHANGED: size = 2; pdu->params[1] = *((uint8_t *)data); break; case AVRCP_EVENT_TRACK_CHANGED: size = 9; memcpy(&pdu->params[1], data, sizeof(uint64_t)); break; case AVRCP_EVENT_TRACK_REACHED_END: case AVRCP_EVENT_TRACK_REACHED_START: size = 1; break; default: error("Unknown event %u", id); return -EINVAL; } pdu->params_len = htons(size); err = avctp_send_vendordep(player->session, player->transaction_events[id], AVC_CTYPE_CHANGED, AVC_SUBUNIT_PANEL, buf, size + AVRCP_HEADER_LENGTH); if (err < 0) return err; /* Unregister event as per AVRCP 1.3 spec, section 5.4.2 */ player->registered_events ^= 1 << id; return 0; } static uint16_t player_write_media_attribute(struct avrcp_player *player, uint32_t id, uint8_t *buf, uint16_t *pos, uint16_t *offset) { uint16_t len; uint16_t attr_len; char valstr[20]; void *value; DBG("%u", id); value = player->cb->get_metadata(id, player->user_data); if (value == NULL) { *offset = 0; return 0; } switch (id) { case AVRCP_MEDIA_ATTRIBUTE_TRACK: case AVRCP_MEDIA_ATTRIBUTE_N_TRACKS: case AVRCP_MEDIA_ATTRIBUTE_DURATION: snprintf(valstr, 20, "%u", GPOINTER_TO_UINT(value)); value = valstr; break; } attr_len = strlen(value); value = ((char *) value) + *offset; len = attr_len - *offset; if (len > AVRCP_PDU_MTU - *pos) { len = AVRCP_PDU_MTU - *pos; *offset += len; } else { *offset = 0; } memcpy(&buf[*pos], value, len); *pos += len; return attr_len; } static GList *player_fill_media_attribute(struct avrcp_player *player, GList *attr_ids, uint8_t *buf, uint16_t *pos, uint16_t *offset) { struct media_attribute_header { uint32_t id; uint16_t charset; uint16_t len; } *hdr = NULL; GList *l; for (l = attr_ids; l != NULL; l = g_list_delete_link(l, l)) { uint32_t attr = GPOINTER_TO_UINT(l->data); uint16_t attr_len; if (*offset == 0) { if (*pos + sizeof(*hdr) >= AVRCP_PDU_MTU) break; hdr = (void *) &buf[*pos]; hdr->id = htonl(attr); hdr->charset = htons(0x6A); /* Always use UTF-8 */ *pos += sizeof(*hdr); } attr_len = player_write_media_attribute(player, attr, buf, pos, offset); if (hdr != NULL) hdr->len = htons(attr_len); if (*offset > 0) break; } return l; } static struct pending_pdu *pending_pdu_new(uint8_t pdu_id, GList *attr_ids, unsigned int offset) { struct pending_pdu *pending = g_new(struct pending_pdu, 1); pending->pdu_id = pdu_id; pending->attr_ids = attr_ids; pending->offset = offset; return pending; } static gboolean player_abort_pending_pdu(struct avrcp_player *player) { if (player->pending_pdu == NULL) return FALSE; g_list_free(player->pending_pdu->attr_ids); g_free(player->pending_pdu); player->pending_pdu = NULL; return TRUE; } static int player_set_attribute(struct avrcp_player *player, uint8_t attr, uint8_t val) { DBG("Change attribute: %u %u", attr, val); return player->cb->set_setting(attr, val, player->user_data); } static int player_get_attribute(struct avrcp_player *player, uint8_t attr) { int value; DBG("attr %u", attr); value = player->cb->get_setting(attr, player->user_data); if (value < 0) DBG("attr %u not supported by player", attr); return value; } static uint8_t avrcp_handle_get_capabilities(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); unsigned int i; if (len != 1) goto err; DBG("id=%u", pdu->params[0]); switch (pdu->params[0]) { case CAP_COMPANY_ID: for (i = 0; i < G_N_ELEMENTS(company_ids); i++) { set_company_id(&pdu->params[2 + i * 3], company_ids[i]); } pdu->params_len = htons(2 + (3 * G_N_ELEMENTS(company_ids))); pdu->params[1] = G_N_ELEMENTS(company_ids); return AVC_CTYPE_STABLE; case CAP_EVENTS_SUPPORTED: pdu->params[1] = 4; pdu->params[2] = AVRCP_EVENT_STATUS_CHANGED; pdu->params[3] = AVRCP_EVENT_TRACK_CHANGED; pdu->params[4] = AVRCP_EVENT_TRACK_REACHED_START; pdu->params[5] = AVRCP_EVENT_TRACK_REACHED_END; pdu->params_len = htons(2 + pdu->params[1]); return AVC_CTYPE_STABLE; } err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static uint8_t avrcp_handle_list_player_attributes(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); unsigned int i; if (len != 0) { pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } if (!player) goto done; for (i = 1; i <= AVRCP_ATTRIBUTE_SCAN; i++) { if (player_get_attribute(player, i) < 0) continue; len++; pdu->params[len] = i; } done: pdu->params[0] = len; pdu->params_len = htons(len + 1); return AVC_CTYPE_STABLE; } static uint8_t avrcp_handle_list_player_values(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); unsigned int i; if (len != 1 || !player) goto err; if (player_get_attribute(player, pdu->params[0]) < 0) goto err; len = attr_get_max_val(pdu->params[0]); for (i = 1; i <= len; i++) pdu->params[i] = i; pdu->params[0] = len; pdu->params_len = htons(len + 1); return AVC_CTYPE_STABLE; err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static uint8_t avrcp_handle_get_element_attributes(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); uint64_t *identifier = (uint64_t *) &pdu->params[0]; uint16_t pos; uint8_t nattr; GList *attr_ids; uint16_t offset; if (len < 9 || *identifier != 0) goto err; nattr = pdu->params[8]; if (len < nattr * sizeof(uint32_t) + 1) goto err; if (!nattr) { /* * Return all available information, at least * title must be returned if there's a track selected. */ attr_ids = player->cb->list_metadata(player->user_data); len = g_list_length(attr_ids); } else { unsigned int i; uint32_t *attr = (uint32_t *) &pdu->params[9]; for (i = 0, len = 0, attr_ids = NULL; i < nattr; i++, attr++) { uint32_t id = ntohl(bt_get_unaligned(attr)); /* Don't add invalid attributes */ if (id == AVRCP_MEDIA_ATTRIBUTE_ILLEGAL || id > AVRCP_MEDIA_ATTRIBUTE_LAST) continue; len++; attr_ids = g_list_prepend(attr_ids, GUINT_TO_POINTER(id)); } attr_ids = g_list_reverse(attr_ids); } if (!len) goto err; player_abort_pending_pdu(player); pos = 1; offset = 0; attr_ids = player_fill_media_attribute(player, attr_ids, pdu->params, &pos, &offset); if (attr_ids != NULL) { player->pending_pdu = pending_pdu_new(pdu->pdu_id, attr_ids, offset); pdu->packet_type = AVRCP_PACKET_TYPE_START; } pdu->params[0] = len; pdu->params_len = htons(pos); return AVC_CTYPE_STABLE; err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static uint8_t avrcp_handle_get_current_player_value(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); uint8_t *settings; unsigned int i; if (player == NULL || len <= 1 || pdu->params[0] != len - 1) goto err; /* * Save a copy of requested settings because we can override them * while responding */ settings = g_memdup(&pdu->params[1], pdu->params[0]); len = 0; /* * From sec. 5.7 of AVRCP 1.3 spec, we should igore non-existent IDs * and send a response with the existent ones. Only if all IDs are * non-existent we should send an error. */ for (i = 0; i < pdu->params[0]; i++) { int val; if (settings[i] < AVRCP_ATTRIBUTE_EQUALIZER || settings[i] > AVRCP_ATTRIBUTE_SCAN) { DBG("Ignoring %u", settings[i]); continue; } val = player_get_attribute(player, settings[i]); if (val < 0) continue; pdu->params[++len] = settings[i]; pdu->params[++len] = val; } g_free(settings); if (len) { pdu->params[0] = len / 2; pdu->params_len = htons(len + 1); return AVC_CTYPE_STABLE; } error("No valid attributes in request"); err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static uint8_t avrcp_handle_set_player_value(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); unsigned int i; uint8_t *param; if (len < 3 || len > 2 * pdu->params[0] + 1U) goto err; /* * From sec. 5.7 of AVRCP 1.3 spec, we should igore non-existent IDs * and set the existent ones. Sec. 5.2.4 is not clear however how to * indicate that a certain ID was not accepted. If at least one * attribute is valid, we respond with no parameters. Otherwise an * E_INVALID_PARAM is sent. */ for (len = 0, i = 0, param = &pdu->params[1]; i < pdu->params[0]; i++, param += 2) { if (player_set_attribute(player, param[0], param[1]) < 0) continue; len++; } if (len) { pdu->params_len = 0; return AVC_CTYPE_ACCEPTED; } err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static uint8_t avrcp_handle_displayable_charset(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); if (len < 3) { pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } /* * We acknowledge the commands, but we always use UTF-8 for * encoding since CT is obliged to support it. */ pdu->params_len = 0; return AVC_CTYPE_STABLE; } static uint8_t avrcp_handle_ct_battery_status(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); const char *valstr; if (len != 1) goto err; valstr = battery_status_to_str(pdu->params[0]); if (valstr == NULL) goto err; pdu->params_len = 0; return AVC_CTYPE_STABLE; err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static uint8_t avrcp_handle_get_play_status(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); uint32_t position; uint32_t duration; void *pduration; if (len != 0) { pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } position = player->cb->get_position(player->user_data); pduration = player->cb->get_metadata(AVRCP_MEDIA_ATTRIBUTE_DURATION, player->user_data); if (pduration != NULL) duration = htonl(GPOINTER_TO_UINT(pduration)); else duration = htonl(UINT32_MAX); position = htonl(position); memcpy(&pdu->params[0], &duration, 4); memcpy(&pdu->params[4], &position, 4); pdu->params[8] = player->cb->get_status(player->user_data);; pdu->params_len = htons(9); return AVC_CTYPE_STABLE; } static uint8_t avrcp_handle_register_notification(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); uint64_t uid; /* * 1 byte for EventID, 4 bytes for Playback interval but the latest * one is applicable only for EVENT_PLAYBACK_POS_CHANGED. See AVRCP * 1.3 spec, section 5.4.2. */ if (len != 5) goto err; switch (pdu->params[0]) { case AVRCP_EVENT_STATUS_CHANGED: len = 2; pdu->params[1] = player->cb->get_status(player->user_data); break; case AVRCP_EVENT_TRACK_CHANGED: len = 9; uid = player->cb->get_uid(player->user_data); memcpy(&pdu->params[1], &uid, sizeof(uint64_t)); break; case AVRCP_EVENT_TRACK_REACHED_END: case AVRCP_EVENT_TRACK_REACHED_START: len = 1; break; default: /* All other events are not supported yet */ goto err; } /* Register event and save the transaction used */ player->registered_events |= (1 << pdu->params[0]); player->transaction_events[pdu->params[0]] = transaction; pdu->params_len = htons(len); return AVC_CTYPE_INTERIM; err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static uint8_t avrcp_handle_request_continuing(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); struct pending_pdu *pending; if (len != 1 || player->pending_pdu == NULL) goto err; pending = player->pending_pdu; if (pending->pdu_id != pdu->params[0]) goto err; len = 0; pending->attr_ids = player_fill_media_attribute(player, pending->attr_ids, pdu->params, &len, &pending->offset); pdu->pdu_id = pending->pdu_id; if (pending->attr_ids == NULL) { g_free(player->pending_pdu); player->pending_pdu = NULL; pdu->packet_type = AVRCP_PACKET_TYPE_END; } else { pdu->packet_type = AVRCP_PACKET_TYPE_CONTINUING; } pdu->params_len = htons(len); return AVC_CTYPE_STABLE; err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static uint8_t avrcp_handle_abort_continuing(struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction) { uint16_t len = ntohs(pdu->params_len); struct pending_pdu *pending; if (len != 1 || player->pending_pdu == NULL) goto err; pending = player->pending_pdu; if (pending->pdu_id != pdu->params[0]) goto err; player_abort_pending_pdu(player); pdu->params_len = 0; return AVC_CTYPE_ACCEPTED; err: pdu->params_len = htons(1); pdu->params[0] = E_INVALID_PARAM; return AVC_CTYPE_REJECTED; } static struct pdu_handler { uint8_t pdu_id; uint8_t code; uint8_t (*func) (struct avrcp_player *player, struct avrcp_header *pdu, uint8_t transaction); } handlers[] = { { AVRCP_GET_CAPABILITIES, AVC_CTYPE_STATUS, avrcp_handle_get_capabilities }, { AVRCP_LIST_PLAYER_ATTRIBUTES, AVC_CTYPE_STATUS, avrcp_handle_list_player_attributes }, { AVRCP_LIST_PLAYER_VALUES, AVC_CTYPE_STATUS, avrcp_handle_list_player_values }, { AVRCP_GET_ELEMENT_ATTRIBUTES, AVC_CTYPE_STATUS, avrcp_handle_get_element_attributes }, { AVRCP_GET_CURRENT_PLAYER_VALUE, AVC_CTYPE_STATUS, avrcp_handle_get_current_player_value }, { AVRCP_SET_PLAYER_VALUE, AVC_CTYPE_CONTROL, avrcp_handle_set_player_value }, { AVRCP_GET_PLAYER_ATTRIBUTE_TEXT, AVC_CTYPE_STATUS, NULL }, { AVRCP_GET_PLAYER_VALUE_TEXT, AVC_CTYPE_STATUS, NULL }, { AVRCP_DISPLAYABLE_CHARSET, AVC_CTYPE_STATUS, avrcp_handle_displayable_charset }, { AVRCP_CT_BATTERY_STATUS, AVC_CTYPE_STATUS, avrcp_handle_ct_battery_status }, { AVRCP_GET_PLAY_STATUS, AVC_CTYPE_STATUS, avrcp_handle_get_play_status }, { AVRCP_REGISTER_NOTIFICATION, AVC_CTYPE_NOTIFY, avrcp_handle_register_notification }, { AVRCP_REQUEST_CONTINUING, AVC_CTYPE_CONTROL, avrcp_handle_request_continuing }, { AVRCP_ABORT_CONTINUING, AVC_CTYPE_CONTROL, avrcp_handle_abort_continuing }, { }, }; /* handle vendordep pdu inside an avctp packet */ static size_t handle_vendordep_pdu(struct avctp *session, uint8_t transaction, uint8_t *code, uint8_t *subunit, uint8_t *operands, size_t operand_count, void *user_data) { struct avrcp_player *player = user_data; struct pdu_handler *handler; struct avrcp_header *pdu = (void *) operands; uint32_t company_id = get_company_id(pdu->company_id); if (company_id != IEEEID_BTSIG) { *code = AVC_CTYPE_NOT_IMPLEMENTED; return 0; } DBG("AVRCP PDU 0x%02X, company 0x%06X len 0x%04X", pdu->pdu_id, company_id, pdu->params_len); pdu->packet_type = 0; pdu->rsvd = 0; if (operand_count < AVRCP_HEADER_LENGTH) { pdu->params[0] = E_INVALID_COMMAND; goto err_metadata; } for (handler = handlers; handler; handler++) { if (handler->pdu_id == pdu->pdu_id) break; } if (!handler || handler->code != *code) { pdu->params[0] = E_INVALID_COMMAND; goto err_metadata; } if (!handler->func) { pdu->params[0] = E_INVALID_PARAM; goto err_metadata; } *code = handler->func(player, pdu, transaction); if (*code != AVC_CTYPE_REJECTED && pdu->pdu_id != AVRCP_GET_ELEMENT_ATTRIBUTES && pdu->pdu_id != AVRCP_REQUEST_CONTINUING && pdu->pdu_id != AVRCP_ABORT_CONTINUING) player_abort_pending_pdu(player); return AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); err_metadata: pdu->params_len = htons(1); *code = AVC_CTYPE_REJECTED; return AVRCP_HEADER_LENGTH + 1; } size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands) { struct avrcp_header *pdu = (void *) operands; uint32_t company_id = get_company_id(pdu->company_id); *code = AVC_CTYPE_REJECTED; pdu->params_len = htons(1); pdu->params[0] = E_INTERNAL; DBG("rejecting AVRCP PDU 0x%02X, company 0x%06X len 0x%04X", pdu->pdu_id, company_id, pdu->params_len); return AVRCP_HEADER_LENGTH + 1; } static struct avrcp_server *find_server(GSList *list, const bdaddr_t *src) { for (; list; list = list->next) { struct avrcp_server *server = list->data; if (bacmp(&server->src, src) == 0) return server; } return NULL; } static gboolean avrcp_handle_volume_changed(struct avctp *session, uint8_t code, uint8_t subunit, uint8_t *operands, size_t operand_count, void *user_data) { struct avrcp_player *player = user_data; struct avrcp_header *pdu = (void *) operands; uint8_t volume; if (code != AVC_CTYPE_INTERIM && code != AVC_CTYPE_CHANGED) return FALSE; volume = pdu->params[1] & 0x7F; player->cb->set_volume(volume, player->dev, player->user_data); if (code == AVC_CTYPE_CHANGED) { register_volume_notification(player); return FALSE; } return TRUE; } static void register_volume_notification(struct avrcp_player *player) { uint8_t buf[AVRCP_HEADER_LENGTH + AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH]; struct avrcp_header *pdu = (void *) buf; uint8_t length; memset(buf, 0, sizeof(buf)); set_company_id(pdu->company_id, IEEEID_BTSIG); pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION; pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE; pdu->params[0] = AVRCP_EVENT_VOLUME_CHANGED; pdu->params_len = htons(AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH); length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len); avctp_send_vendordep_req(player->session, AVC_CTYPE_NOTIFY, AVC_SUBUNIT_PANEL, buf, length, avrcp_handle_volume_changed, player); } static void state_changed(struct audio_device *dev, avctp_state_t old_state, avctp_state_t new_state, void *user_data) { struct avrcp_server *server; struct avrcp_player *player; const sdp_record_t *rec; sdp_list_t *list; sdp_profile_desc_t *desc; server = find_server(servers, &dev->src); if (!server) return; player = server->active_player; if (!player) return; switch (new_state) { case AVCTP_STATE_DISCONNECTED: player->session = NULL; player->dev = NULL; player->registered_events = 0; if (player->handler) { avctp_unregister_pdu_handler(player->handler); player->handler = 0; } break; case AVCTP_STATE_CONNECTING: player->session = avctp_connect(&dev->src, &dev->dst); player->dev = dev; if (!player->handler) player->handler = avctp_register_pdu_handler( AVC_OP_VENDORDEP, handle_vendordep_pdu, player); break; case AVCTP_STATE_CONNECTED: rec = btd_device_get_record(dev->btd_dev, AVRCP_TARGET_UUID); if (rec == NULL) return; if (sdp_get_profile_descs(rec, &list) < 0) return; desc = list->data; if (desc && desc->version >= 0x0104) register_volume_notification(player); sdp_list_free(list, free); default: return; } } gboolean avrcp_connect(struct audio_device *dev) { struct avctp *session; session = avctp_connect(&dev->src, &dev->dst); if (session) return FALSE; return TRUE; } void avrcp_disconnect(struct audio_device *dev) { struct avctp *session; session = avctp_get(&dev->src, &dev->dst); if (!session) return; avctp_disconnect(session); } int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config) { sdp_record_t *record; gboolean tmp, master = TRUE; GError *err = NULL; struct avrcp_server *server; if (config) { tmp = g_key_file_get_boolean(config, "General", "Master", &err); if (err) { DBG("audio.conf: %s", err->message); g_error_free(err); } else master = tmp; } server = g_new0(struct avrcp_server, 1); if (!server) return -ENOMEM; record = avrcp_tg_record(); if (!record) { error("Unable to allocate new service record"); g_free(server); return -1; } if (add_record_to_server(src, record) < 0) { error("Unable to register AVRCP target service record"); g_free(server); sdp_record_free(record); return -1; } server->tg_record_id = record->handle; record = avrcp_ct_record(); if (!record) { error("Unable to allocate new service record"); g_free(server); return -1; } if (add_record_to_server(src, record) < 0) { error("Unable to register AVRCP service record"); sdp_record_free(record); g_free(server); return -1; } server->ct_record_id = record->handle; if (avctp_register(src, master) < 0) { remove_record_from_server(server->ct_record_id); remove_record_from_server(server->tg_record_id); g_free(server); return -1; } bacpy(&server->src, src); servers = g_slist_append(servers, server); return 0; } static void player_destroy(gpointer data) { struct avrcp_player *player = data; if (player->destroy) player->destroy(player->user_data); player_abort_pending_pdu(player); if (player->handler) avctp_unregister_pdu_handler(player->handler); g_free(player); } void avrcp_unregister(const bdaddr_t *src) { struct avrcp_server *server; server = find_server(servers, src); if (!server) return; g_slist_free_full(server->players, player_destroy); servers = g_slist_remove(servers, server); remove_record_from_server(server->ct_record_id); remove_record_from_server(server->tg_record_id); avctp_unregister(&server->src); g_free(server); if (servers) return; if (avctp_id) { avctp_remove_state_cb(avctp_id); avctp_id = 0; } } struct avrcp_player *avrcp_register_player(const bdaddr_t *src, struct avrcp_player_cb *cb, void *user_data, GDestroyNotify destroy) { struct avrcp_server *server; struct avrcp_player *player; server = find_server(servers, src); if (!server) return NULL; player = g_new0(struct avrcp_player, 1); player->server = server; player->cb = cb; player->user_data = user_data; player->destroy = destroy; if (!server->players) server->active_player = player; if (!avctp_id) avctp_id = avctp_add_state_cb(state_changed, NULL); server->players = g_slist_append(server->players, player); return player; } void avrcp_unregister_player(struct avrcp_player *player) { struct avrcp_server *server = player->server; server->players = g_slist_remove(server->players, player); if (server->active_player == player) server->active_player = g_slist_nth_data(server->players, 0); player_destroy(player); } static gboolean avrcp_handle_set_volume(struct avctp *session, uint8_t code, uint8_t subunit, uint8_t *operands, size_t operand_count, void *user_data) { struct avrcp_player *player = user_data; struct avrcp_header *pdu = (void *) operands; uint8_t volume; if (code == AVC_CTYPE_REJECTED || code == AVC_CTYPE_NOT_IMPLEMENTED) return FALSE; volume = pdu->params[0] & 0x7F; player->cb->set_volume(volume, player->dev, player->user_data); return FALSE; } int avrcp_set_volume(struct audio_device *dev, uint8_t volume) { struct avrcp_server *server; struct avrcp_player *player; uint8_t buf[AVRCP_HEADER_LENGTH + 1]; struct avrcp_header *pdu = (void *) buf; server = find_server(servers, &dev->src); if (server == NULL) return -EINVAL; player = server->active_player; if (player == NULL) return -ENOTSUP; if (player->session == NULL) return -ENOTCONN; memset(buf, 0, sizeof(buf)); set_company_id(pdu->company_id, IEEEID_BTSIG); pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME; pdu->params[0] = volume; pdu->params_len = htons(1); DBG("volume=%u", volume); return avctp_send_vendordep_req(player->session, AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL, buf, sizeof(buf), avrcp_handle_set_volume, player); } bluez-4.101/audio/telephony.h0000644000000000000000000001776711571052274013036 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include /* Response and hold values */ #define BTRH_NOT_SUPPORTED -2 #define BTRH_NONE -1 #define BTRH_HOLD 0 #define BTRH_ACCEPT 1 #define BTRH_REJECT 2 /* HFP feature bits */ #define AG_FEATURE_THREE_WAY_CALLING 0x0001 #define AG_FEATURE_EC_ANDOR_NR 0x0002 #define AG_FEATURE_VOICE_RECOGNITION 0x0004 #define AG_FEATURE_INBAND_RINGTONE 0x0008 #define AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG 0x0010 #define AG_FEATURE_REJECT_A_CALL 0x0020 #define AG_FEATURE_ENHANCED_CALL_STATUS 0x0040 #define AG_FEATURE_ENHANCED_CALL_CONTROL 0x0080 #define AG_FEATURE_EXTENDED_ERROR_RESULT_CODES 0x0100 #define HF_FEATURE_EC_ANDOR_NR 0x0001 #define HF_FEATURE_CALL_WAITING_AND_3WAY 0x0002 #define HF_FEATURE_CLI_PRESENTATION 0x0004 #define HF_FEATURE_VOICE_RECOGNITION 0x0008 #define HF_FEATURE_REMOTE_VOLUME_CONTROL 0x0010 #define HF_FEATURE_ENHANCED_CALL_STATUS 0x0020 #define HF_FEATURE_ENHANCED_CALL_CONTROL 0x0040 /* Indicator event values */ #define EV_SERVICE_NONE 0 #define EV_SERVICE_PRESENT 1 #define EV_CALL_INACTIVE 0 #define EV_CALL_ACTIVE 1 #define EV_CALLSETUP_INACTIVE 0 #define EV_CALLSETUP_INCOMING 1 #define EV_CALLSETUP_OUTGOING 2 #define EV_CALLSETUP_ALERTING 3 #define EV_CALLHELD_NONE 0 #define EV_CALLHELD_MULTIPLE 1 #define EV_CALLHELD_ON_HOLD 2 #define EV_ROAM_INACTIVE 0 #define EV_ROAM_ACTIVE 1 /* Call parameters */ #define CALL_DIR_OUTGOING 0 #define CALL_DIR_INCOMING 1 #define CALL_STATUS_ACTIVE 0 #define CALL_STATUS_HELD 1 #define CALL_STATUS_DIALING 2 #define CALL_STATUS_ALERTING 3 #define CALL_STATUS_INCOMING 4 #define CALL_STATUS_WAITING 5 #define CALL_MODE_VOICE 0 #define CALL_MODE_DATA 1 #define CALL_MODE_FAX 2 #define CALL_MULTIPARTY_NO 0 #define CALL_MULTIPARTY_YES 1 /* Subscriber number parameters */ #define SUBSCRIBER_SERVICE_VOICE 4 #define SUBSCRIBER_SERVICE_FAX 5 /* Operator selection mode values */ #define OPERATOR_MODE_AUTO 0 #define OPERATOR_MODE_MANUAL 1 #define OPERATOR_MODE_DEREGISTER 2 #define OPERATOR_MODE_MANUAL_AUTO 4 /* Some common number types */ #define NUMBER_TYPE_UNKNOWN 128 #define NUMBER_TYPE_TELEPHONY 129 #define NUMBER_TYPE_INTERNATIONAL 145 #define NUMBER_TYPE_NATIONAL 161 #define NUMBER_TYPE_VOIP 255 /* Extended Audio Gateway Error Result Codes */ typedef enum { CME_ERROR_NONE = -1, CME_ERROR_AG_FAILURE = 0, CME_ERROR_NO_PHONE_CONNECTION = 1, CME_ERROR_NOT_ALLOWED = 3, CME_ERROR_NOT_SUPPORTED = 4, CME_ERROR_PH_SIM_PIN_REQUIRED = 5, CME_ERROR_SIM_NOT_INSERTED = 10, CME_ERROR_SIM_PIN_REQUIRED = 11, CME_ERROR_SIM_PUK_REQUIRED = 12, CME_ERROR_SIM_FAILURE = 13, CME_ERROR_SIM_BUSY = 14, CME_ERROR_INCORRECT_PASSWORD = 16, CME_ERROR_SIM_PIN2_REQUIRED = 17, CME_ERROR_SIM_PUK2_REQUIRED = 18, CME_ERROR_MEMORY_FULL = 20, CME_ERROR_INVALID_INDEX = 21, CME_ERROR_MEMORY_FAILURE = 23, CME_ERROR_TEXT_STRING_TOO_LONG = 24, CME_ERROR_INVALID_TEXT_STRING = 25, CME_ERROR_DIAL_STRING_TOO_LONG = 26, CME_ERROR_INVALID_DIAL_STRING = 27, CME_ERROR_NO_NETWORK_SERVICE = 30, CME_ERROR_NETWORK_TIMEOUT = 31, CME_ERROR_NETWORK_NOT_ALLOWED = 32, } cme_error_t; struct indicator { const char *desc; const char *range; int val; gboolean ignore_redundant; }; /* Notify telephony-*.c of connected/disconnected devices. Implemented by * telephony-*.c */ void telephony_device_connected(void *telephony_device); void telephony_device_disconnected(void *telephony_device); /* HF requests (sent by the handsfree device). These are implemented by * telephony-*.c */ void telephony_event_reporting_req(void *telephony_device, int ind); void telephony_response_and_hold_req(void *telephony_device, int rh); void telephony_last_dialed_number_req(void *telephony_device); void telephony_terminate_call_req(void *telephony_device); void telephony_answer_call_req(void *telephony_device); void telephony_dial_number_req(void *telephony_device, const char *number); void telephony_transmit_dtmf_req(void *telephony_device, char tone); void telephony_subscriber_number_req(void *telephony_device); void telephony_list_current_calls_req(void *telephony_device); void telephony_operator_selection_req(void *telephony_device); void telephony_call_hold_req(void *telephony_device, const char *cmd); void telephony_nr_and_ec_req(void *telephony_device, gboolean enable); void telephony_voice_dial_req(void *telephony_device, gboolean enable); void telephony_key_press_req(void *telephony_device, const char *keys); /* AG responses to HF requests. These are implemented by headset.c */ int telephony_event_reporting_rsp(void *telephony_device, cme_error_t err); int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err); int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err); int telephony_terminate_call_rsp(void *telephony_device, cme_error_t err); int telephony_answer_call_rsp(void *telephony_device, cme_error_t err); int telephony_dial_number_rsp(void *telephony_device, cme_error_t err); int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err); int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err); int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err); int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err); int telephony_call_hold_rsp(void *telephony_device, cme_error_t err); int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err); int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err); int telephony_key_press_rsp(void *telephony_device, cme_error_t err); /* Event indications by AG. These are implemented by headset.c */ int telephony_event_ind(int index); int telephony_response_and_hold_ind(int rh); int telephony_incoming_call_ind(const char *number, int type); int telephony_calling_stopped_ind(void); int telephony_ready_ind(uint32_t features, const struct indicator *indicators, int rh, const char *chld); int telephony_deinit(void); int telephony_list_current_call_ind(int idx, int dir, int status, int mode, int mprty, const char *number, int type); int telephony_subscriber_number_ind(const char *number, int type, int service); int telephony_call_waiting_ind(const char *number, int type); int telephony_operator_selection_ind(int mode, const char *oper); /* Helper function for quick indicator updates */ static inline int telephony_update_indicator(struct indicator *indicators, const char *desc, int new_val) { int i; struct indicator *ind = NULL; for (i = 0; indicators[i].desc != NULL; i++) { if (g_str_equal(indicators[i].desc, desc)) { ind = &indicators[i]; break; } } if (!ind) return -ENOENT; DBG("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val); if (ind->ignore_redundant && ind->val == new_val) { DBG("Ignoring no-change indication"); return 0; } ind->val = new_val; return telephony_event_ind(i); } static inline int telephony_get_indicator(const struct indicator *indicators, const char *desc) { int i; for (i = 0; indicators[i].desc != NULL; i++) { if (g_str_equal(indicators[i].desc, desc)) return indicators[i].val; } return -ENOENT; } int telephony_init(void); void telephony_exit(void); bluez-4.101/audio/bluetooth.conf0000644000000000000000000000101311177423345013506 00000000000000# Please note that this ALSA configuration file fragment needs be enabled in # /etc/asound.conf or a similar configuration file with directives similar to # the following: # #@hooks [ # { # func load # files [ # "/etc/alsa/bluetooth.conf" # ] # errors false # } #] pcm.rawbluetooth { @args [ ADDRESS ] @args.ADDRESS { type string } type bluetooth device $ADDRESS } pcm.bluetooth { @args [ ADDRESS ] @args.ADDRESS { type string } type plug slave { pcm { type bluetooth device $ADDRESS } } } bluez-4.101/audio/source.h0000644000000000000000000000350611766125764012324 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2009 Joao Paulo Rechi Vita * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define AUDIO_SOURCE_INTERFACE "org.bluez.AudioSource" typedef enum { SOURCE_STATE_DISCONNECTED, SOURCE_STATE_CONNECTING, SOURCE_STATE_CONNECTED, SOURCE_STATE_PLAYING, } source_state_t; typedef void (*source_state_cb) (struct audio_device *dev, source_state_t old_state, source_state_t new_state, void *user_data); unsigned int source_add_state_cb(source_state_cb cb, void *user_data); gboolean source_remove_state_cb(unsigned int id); struct source *source_init(struct audio_device *dev); void source_unregister(struct audio_device *dev); gboolean source_is_active(struct audio_device *dev); source_state_t source_get_state(struct audio_device *dev); gboolean source_new_stream(struct audio_device *dev, struct avdtp *session, struct avdtp_stream *stream); gboolean source_setup_stream(struct source *source, struct avdtp *session); gboolean source_shutdown(struct source *source); bluez-4.101/audio/telephony-maemo6.c0000644000000000000000000015035111766125764014211 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "telephony.h" #include "error.h" /* SSC D-Bus definitions */ #define SSC_DBUS_NAME "com.nokia.phone.SSC" #define SSC_DBUS_IFACE "com.nokia.phone.SSC" #define SSC_DBUS_PATH "/com/nokia/phone/SSC" /* libcsnet D-Bus definitions */ #define CSD_CSNET_BUS_NAME "com.nokia.csd.CSNet" #define CSD_CSNET_PATH "/com/nokia/csd/csnet" #define CSD_CSNET_IFACE "com.nokia.csd.CSNet" #define CSD_CSNET_REGISTRATION "com.nokia.csd.CSNet.NetworkRegistration" #define CSD_CSNET_OPERATOR "com.nokia.csd.CSNet.NetworkOperator" #define CSD_CSNET_SIGNAL "com.nokia.csd.CSNet.SignalStrength" enum net_registration_status { NETWORK_REG_STATUS_HOME, NETWORK_REG_STATUS_ROAMING, NETWORK_REG_STATUS_OFFLINE, NETWORK_REG_STATUS_SEARCHING, NETWORK_REG_STATUS_NO_SIM, NETWORK_REG_STATUS_POWEROFF, NETWORK_REG_STATUS_POWERSAFE, NETWORK_REG_STATUS_NO_COVERAGE, NETWORK_REG_STATUS_REJECTED, NETWORK_REG_STATUS_UNKOWN }; /* CSD CALL plugin D-Bus definitions */ #define CSD_CALL_BUS_NAME "com.nokia.csd.Call" #define CSD_CALL_INTERFACE "com.nokia.csd.Call" #define CSD_CALL_INSTANCE "com.nokia.csd.Call.Instance" #define CSD_CALL_CONFERENCE "com.nokia.csd.Call.Conference" #define CSD_CALL_PATH "/com/nokia/csd/call" #define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference" /* Call status values as exported by the CSD CALL plugin */ #define CSD_CALL_STATUS_IDLE 0 #define CSD_CALL_STATUS_CREATE 1 #define CSD_CALL_STATUS_COMING 2 #define CSD_CALL_STATUS_PROCEEDING 3 #define CSD_CALL_STATUS_MO_ALERTING 4 #define CSD_CALL_STATUS_MT_ALERTING 5 #define CSD_CALL_STATUS_WAITING 6 #define CSD_CALL_STATUS_ANSWERED 7 #define CSD_CALL_STATUS_ACTIVE 8 #define CSD_CALL_STATUS_MO_RELEASE 9 #define CSD_CALL_STATUS_MT_RELEASE 10 #define CSD_CALL_STATUS_HOLD_INITIATED 11 #define CSD_CALL_STATUS_HOLD 12 #define CSD_CALL_STATUS_RETRIEVE_INITIATED 13 #define CSD_CALL_STATUS_RECONNECT_PENDING 14 #define CSD_CALL_STATUS_TERMINATED 15 #define CSD_CALL_STATUS_SWAP_INITIATED 16 #define CALL_FLAG_NONE 0 #define CALL_FLAG_PRESENTATION_ALLOWED 0x01 #define CALL_FLAG_PRESENTATION_RESTRICTED 0x02 /* SIM Phonebook D-Bus definitions */ #define CSD_SIMPB_BUS_NAME "com.nokia.csd.SIM" #define CSD_SIMPB_INTERFACE "com.nokia.csd.SIM.Phonebook" #define CSD_SIMPB_PATH "/com/nokia/csd/sim/phonebook" #define CSD_SIMPB_TYPE_ADN "ADN" #define CSD_SIMPB_TYPE_FDN "FDN" #define CSD_SIMPB_TYPE_SDN "SDN" #define CSD_SIMPB_TYPE_VMBX "VMBX" #define CSD_SIMPB_TYPE_MBDN "MBDN" #define CSD_SIMPB_TYPE_EN "EN" #define CSD_SIMPB_TYPE_MSISDN "MSISDN" /* OHM plugin D-Bus definitions */ #define OHM_BUS_NAME "com.nokia.NonGraphicFeedback1" #define OHM_INTERFACE "com.nokia.NonGraphicFeedback1" #define OHM_PATH "/com/nokia/NonGraphicFeedback1" /* tone-genenerator D-Bus definitions */ #define TONEGEN_BUS_NAME "com.Nokia.Telephony.Tones" #define TONEGEN_INTERFACE "com.Nokia.Telephony.Tones" #define TONEGEN_PATH "/com/Nokia/Telephony/Tones" /* tone-generator DTMF definitions */ #define DTMF_ASTERISK 10 #define DTMF_HASHMARK 11 #define DTMF_A 12 #define DTMF_B 13 #define DTMF_C 14 #define DTMF_D 15 #define FEEDBACK_TONE_DURATION 200 struct csd_call { char *object_path; int status; gboolean originating; gboolean emergency; gboolean on_hold; gboolean conference; char *number; gboolean setup; }; static struct { char *operator_name; uint8_t status; int32_t signal_bars; } net = { .operator_name = NULL, .status = NETWORK_REG_STATUS_UNKOWN, /* Init as 0 meaning inactive mode. In modem power off state * can be be -1, but we treat all values as 0s regardless * inactive or power off. */ .signal_bars = 0, }; struct pending_req { DBusPendingCall *call; void *user_data; }; static int get_property(const char *iface, const char *prop); static DBusConnection *connection = NULL; static GSList *calls = NULL; static GSList *watches = NULL; static GSList *pending = NULL; /* Reference count for determining the call indicator status */ static GSList *active_calls = NULL; /* Queue of DTMF tones to play */ static GSList *tones = NULL; static guint create_tones_timer = 0; static char *msisdn = NULL; /* Subscriber number */ static char *vmbx = NULL; /* Voice mailbox number */ /* HAL battery namespace key values */ static int battchg_cur = -1; /* "battery.charge_level.current" */ static int battchg_last = -1; /* "battery.charge_level.last_full" */ static int battchg_design = -1; /* "battery.charge_level.design" */ static gboolean get_calls_active = FALSE; static gboolean events_enabled = FALSE; /* Supported set of call hold operations */ static const char *chld_str = "0,1,1x,2,2x,3,4"; /* Timer for tracking call creation requests */ static guint create_request_timer = 0; static struct indicator maemo_indicators[] = { { "battchg", "0-5", 5, TRUE }, /* signal strength in terms of bars */ { "signal", "0-5", 0, TRUE }, { "service", "0,1", 0, TRUE }, { "call", "0,1", 0, TRUE }, { "callsetup", "0-3", 0, TRUE }, { "callheld", "0-2", 0, FALSE }, { "roam", "0,1", 0, TRUE }, { NULL } }; static char *call_status_str[] = { "IDLE", "CREATE", "COMING", "PROCEEDING", "MO_ALERTING", "MT_ALERTING", "WAITING", "ANSWERED", "ACTIVE", "MO_RELEASE", "MT_RELEASE", "HOLD_INITIATED", "HOLD", "RETRIEVE_INITIATED", "RECONNECT_PENDING", "TERMINATED", "SWAP_INITIATED", "???" }; static int send_method_call(const char *dest, const char *path, const char *interface, const char *method, DBusPendingCallNotifyFunction cb, void *user_data, int type, ...) { DBusMessage *msg; DBusPendingCall *call; va_list args; struct pending_req *req; msg = dbus_message_new_method_call(dest, path, interface, method); if (!msg) { error("Unable to allocate new D-Bus %s message", method); return -ENOMEM; } va_start(args, type); if (!dbus_message_append_args_valist(msg, type, args)) { dbus_message_unref(msg); va_end(args); return -EIO; } va_end(args); if (!cb) { g_dbus_send_message(connection, msg); return 0; } if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) { error("Sending %s failed", method); dbus_message_unref(msg); return -EIO; } dbus_pending_call_set_notify(call, cb, user_data, NULL); req = g_new0(struct pending_req, 1); req->call = call; req->user_data = user_data; pending = g_slist_prepend(pending, req); dbus_message_unref(msg); return 0; } static struct csd_call *find_call(const char *path) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (g_str_equal(call->object_path, path)) return call; } return NULL; } static struct csd_call *find_non_held_call(void) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (call->status == CSD_CALL_STATUS_IDLE) continue; if (call->status != CSD_CALL_STATUS_HOLD) return call; } return NULL; } static struct csd_call *find_non_idle_call(void) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (call->status != CSD_CALL_STATUS_IDLE) return call; } return NULL; } static struct csd_call *find_call_with_status(int status) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (call->status == status) return call; } return NULL; } static int release_conference(void) { DBusMessage *msg; DBG("telephony-maemo6: releasing conference call"); msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_CONFERENCE_PATH, CSD_CALL_INSTANCE, "Release"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int release_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, call->object_path, CSD_CALL_INSTANCE, "Release"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int answer_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, call->object_path, CSD_CALL_INSTANCE, "Answer"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static struct pending_req *find_request(const DBusPendingCall *call) { GSList *l; for (l = pending; l; l = l->next) { struct pending_req *req = l->data; if (req->call == call) return req; } return NULL; } static void pending_req_finalize(void *data) { struct pending_req *req = data; if (!dbus_pending_call_get_completed(req->call)) dbus_pending_call_cancel(req->call); dbus_pending_call_unref(req->call); g_free(req); } static void remove_pending(DBusPendingCall *call) { struct pending_req *req = find_request(call); pending = g_slist_remove(pending, req); pending_req_finalize(req); } static void stop_ringtone_reply(DBusPendingCall *call, void *user_data) { struct csd_call *coming = user_data; remove_pending(call); answer_call(coming); } static int stop_ringtone_and_answer(struct csd_call *call) { int ret; ret = send_method_call(OHM_BUS_NAME, OHM_PATH, OHM_INTERFACE, "StopRingtone", stop_ringtone_reply, call, DBUS_TYPE_INVALID); if (ret < 0) return answer_call(call); return 0; } static int split_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, call->object_path, CSD_CALL_INSTANCE, "Split"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int unhold_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Unhold"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int hold_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Hold"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int swap_calls(void) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Swap"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int create_conference(void) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Conference"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int call_transfer(void) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Transfer"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int number_type(const char *number) { if (number == NULL) return NUMBER_TYPE_TELEPHONY; if (number[0] == '+' || strncmp(number, "00", 2) == 0) return NUMBER_TYPE_INTERNATIONAL; return NUMBER_TYPE_TELEPHONY; } void telephony_device_connected(void *telephony_device) { struct csd_call *coming; DBG("telephony-maemo6: device %p connected", telephony_device); coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING); if (coming) { if (find_call_with_status(CSD_CALL_STATUS_ACTIVE)) telephony_call_waiting_ind(coming->number, number_type(coming->number)); else telephony_incoming_call_ind(coming->number, number_type(coming->number)); } } static void remove_pending_by_data(gpointer data, gpointer user_data) { struct pending_req *req = data; if (req->user_data == user_data) { pending = g_slist_remove(pending, req); pending_req_finalize(req); } } void telephony_device_disconnected(void *telephony_device) { DBG("telephony-maemo6: device %p disconnected", telephony_device); events_enabled = FALSE; g_slist_foreach(pending, remove_pending_by_data, telephony_device); } void telephony_event_reporting_req(void *telephony_device, int ind) { events_enabled = ind == 1 ? TRUE : FALSE; telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE); } void telephony_response_and_hold_req(void *telephony_device, int rh) { telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED); } void telephony_terminate_call_req(void *telephony_device) { struct csd_call *call; struct csd_call *alerting; int err; call = find_call_with_status(CSD_CALL_STATUS_ACTIVE); if (!call) call = find_non_idle_call(); if (!call) { error("No active call"); telephony_terminate_call_rsp(telephony_device, CME_ERROR_NOT_ALLOWED); return; } alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING); if (call->on_hold && alerting) err = release_call(alerting); else if (call->conference) err = release_conference(); else err = release_call(call); if (err < 0) telephony_terminate_call_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE); } void telephony_answer_call_req(void *telephony_device) { struct csd_call *call; call = find_call_with_status(CSD_CALL_STATUS_COMING); if (!call) call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING); if (!call) call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING); if (!call) call = find_call_with_status(CSD_CALL_STATUS_WAITING); if (!call) { telephony_answer_call_rsp(telephony_device, CME_ERROR_NOT_ALLOWED); return; } if (stop_ringtone_and_answer(call) < 0) telephony_answer_call_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE); } static void create_call_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; void *telephony_device = user_data; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("csd replied with an error: %s, %s", err.name, err.message); if (g_strcmp0(err.name, "com.nokia.csd.Call.Error.CSInactive") == 0) telephony_dial_number_rsp(telephony_device, CME_ERROR_NO_NETWORK_SERVICE); else telephony_dial_number_rsp(telephony_device, CME_ERROR_AG_FAILURE); dbus_error_free(&err); } else telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE); dbus_message_unref(reply); remove_pending(call); } void telephony_last_dialed_number_req(void *telephony_device) { int ret; DBG("telephony-maemo6: last dialed number request"); ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "CreateFromLast", create_call_reply, telephony_device, DBUS_TYPE_INVALID); if (ret < 0) telephony_dial_number_rsp(telephony_device, CME_ERROR_AG_FAILURE); } static const char *memory_dial_lookup(int location) { if (location == 1) return vmbx; else return NULL; } void telephony_dial_number_req(void *telephony_device, const char *number) { int ret; DBG("telephony-maemo6: dial request to %s", number); if (strncmp(number, "*31#", 4) == 0) number += 4; else if (strncmp(number, "#31#", 4) == 0) number += 4; else if (number[0] == '>') { const char *location = &number[1]; number = memory_dial_lookup(strtol(&number[1], NULL, 0)); if (!number) { error("No number at memory location %s", location); telephony_dial_number_rsp(telephony_device, CME_ERROR_INVALID_INDEX); return; } } ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Create", create_call_reply, telephony_device, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID); if (ret < 0) telephony_dial_number_rsp(telephony_device, CME_ERROR_AG_FAILURE); } static void start_dtmf_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("csd replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); } else send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "StopDTMF", NULL, NULL, DBUS_TYPE_INVALID); dbus_message_unref(reply); remove_pending(call); } static void start_dtmf(void *telephony_device, char tone) { int ret; /* * Stop tone immediately, modem will place it in queue and play * required time. */ ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "StartDTMF", start_dtmf_reply, NULL, DBUS_TYPE_BYTE, &tone, DBUS_TYPE_INVALID); if (ret < 0) { telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_AG_FAILURE); return; } telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE); } static int tonegen_startevent(char tone) { int ret; dbus_uint32_t event_tone; dbus_int32_t dbm0 = -15; dbus_uint32_t duration = 150; switch (tone) { case '*': event_tone = DTMF_ASTERISK; break; case '#': event_tone = DTMF_HASHMARK; break; case 'A': event_tone = DTMF_A; break; case 'B': event_tone = DTMF_B; break; case 'C': event_tone = DTMF_C; break; case 'D': event_tone = DTMF_D; break; default: ret = g_ascii_digit_value(tone); if (ret < 0) return -EINVAL; event_tone = ret; } ret = send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH, TONEGEN_INTERFACE, "StartEventTone", NULL, NULL, DBUS_TYPE_UINT32, &event_tone, DBUS_TYPE_INT32, &dbm0, DBUS_TYPE_UINT32, &duration, DBUS_TYPE_INVALID); return ret; } static gboolean stop_feedback_tone(gpointer user_data) { if (g_slist_length(tones) > 0) { gpointer ptone; int ret; send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH, TONEGEN_INTERFACE, "StopTone", NULL, NULL, DBUS_TYPE_INVALID); ptone = g_slist_nth_data(tones, 0); tones = g_slist_remove(tones, ptone); ret = tonegen_startevent(GPOINTER_TO_UINT(ptone)); if (ret < 0) goto done; return TRUE; } done: return FALSE; } static void tones_timer_notify(gpointer data) { send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH, TONEGEN_INTERFACE, "StopTone", NULL, NULL, DBUS_TYPE_INVALID); g_slist_free(tones); tones = NULL; create_tones_timer = 0; } static void start_feedback_tone(char tone) { if (!create_tones_timer) { int ret; ret = tonegen_startevent(tone); if (ret < 0) return; create_tones_timer = g_timeout_add_full(G_PRIORITY_DEFAULT, FEEDBACK_TONE_DURATION, stop_feedback_tone, NULL, tones_timer_notify); } else { glong dtmf_tone = tone; DBG("add %c to queue", tone); tones = g_slist_append(tones, GUINT_TO_POINTER(dtmf_tone)); } } void telephony_transmit_dtmf_req(void *telephony_device, char tone) { DBG("telephony-maemo6: transmit dtmf: %c", tone); start_dtmf(telephony_device, tone); if (!find_call_with_status(CSD_CALL_STATUS_ACTIVE)) error("No active call"); else start_feedback_tone(tone); } void telephony_subscriber_number_req(void *telephony_device) { DBG("telephony-maemo6: subscriber number request"); if (msisdn) telephony_subscriber_number_ind(msisdn, number_type(msisdn), SUBSCRIBER_SERVICE_VOICE); telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE); } static int csd_status_to_hfp(struct csd_call *call) { switch (call->status) { case CSD_CALL_STATUS_IDLE: case CSD_CALL_STATUS_MO_RELEASE: case CSD_CALL_STATUS_MT_RELEASE: case CSD_CALL_STATUS_TERMINATED: return -1; case CSD_CALL_STATUS_CREATE: return CALL_STATUS_DIALING; case CSD_CALL_STATUS_WAITING: return CALL_STATUS_WAITING; case CSD_CALL_STATUS_PROCEEDING: /* PROCEEDING can happen in outgoing/incoming */ if (call->originating) return CALL_STATUS_DIALING; /* * PROCEEDING is followed by WAITING CSD status, therefore * second incoming call status indication is set immediately * to waiting. */ if (g_slist_length(active_calls) > 0) return CALL_STATUS_WAITING; return CALL_STATUS_INCOMING; case CSD_CALL_STATUS_COMING: if (g_slist_length(active_calls) > 0) return CALL_STATUS_WAITING; return CALL_STATUS_INCOMING; case CSD_CALL_STATUS_MO_ALERTING: return CALL_STATUS_ALERTING; case CSD_CALL_STATUS_MT_ALERTING: return CALL_STATUS_INCOMING; case CSD_CALL_STATUS_ANSWERED: case CSD_CALL_STATUS_ACTIVE: case CSD_CALL_STATUS_RECONNECT_PENDING: case CSD_CALL_STATUS_SWAP_INITIATED: case CSD_CALL_STATUS_HOLD_INITIATED: return CALL_STATUS_ACTIVE; case CSD_CALL_STATUS_RETRIEVE_INITIATED: case CSD_CALL_STATUS_HOLD: return CALL_STATUS_HELD; default: return -1; } } void telephony_list_current_calls_req(void *telephony_device) { GSList *l; int i; DBG("telephony-maemo6: list current calls request"); for (l = calls, i = 1; l != NULL; l = l->next, i++) { struct csd_call *call = l->data; int status, direction, multiparty; status = csd_status_to_hfp(call); if (status < 0) continue; direction = call->originating ? CALL_DIR_OUTGOING : CALL_DIR_INCOMING; multiparty = call->conference ? CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO; telephony_list_current_call_ind(i, direction, status, CALL_MODE_VOICE, multiparty, call->number, number_type(call->number)); } telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE); } void telephony_operator_selection_req(void *telephony_device) { telephony_operator_selection_ind(OPERATOR_MODE_AUTO, net.operator_name ? net.operator_name : ""); telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE); } static void foreach_call_with_status(int status, int (*func)(struct csd_call *call)) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (call->status == status) func(call); } } void telephony_call_hold_req(void *telephony_device, const char *cmd) { const char *idx; struct csd_call *call; int err = 0; DBG("telephony-maemo6: got call hold request %s", cmd); if (strlen(cmd) > 1) idx = &cmd[1]; else idx = NULL; if (idx) call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1); else call = NULL; switch (cmd[0]) { case '0': if (find_call_with_status(CSD_CALL_STATUS_WAITING)) foreach_call_with_status(CSD_CALL_STATUS_WAITING, release_call); else foreach_call_with_status(CSD_CALL_STATUS_HOLD, release_call); break; case '1': if (idx) { if (call) err = release_call(call); break; } foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call); call = find_call_with_status(CSD_CALL_STATUS_WAITING); if (call) err = answer_call(call); break; case '2': if (idx) { if (call) err = split_call(call); } else { struct csd_call *held, *wait; call = find_call_with_status(CSD_CALL_STATUS_ACTIVE); held = find_call_with_status(CSD_CALL_STATUS_HOLD); wait = find_call_with_status(CSD_CALL_STATUS_WAITING); if (wait) err = answer_call(wait); else if (call && held) err = swap_calls(); else { if (call) err = hold_call(call); if (held) err = unhold_call(held); } } break; case '3': if (find_call_with_status(CSD_CALL_STATUS_HOLD) || find_call_with_status(CSD_CALL_STATUS_WAITING)) err = create_conference(); break; case '4': err = call_transfer(); break; default: DBG("Unknown call hold request"); break; } if (err) telephony_call_hold_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE); } void telephony_nr_and_ec_req(void *telephony_device, gboolean enable) { DBG("telephony-maemo6: got %s NR and EC request", enable ? "enable" : "disable"); telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE); } void telephony_key_press_req(void *telephony_device, const char *keys) { struct csd_call *active, *waiting; int err; DBG("telephony-maemo6: got key press request for %s", keys); waiting = find_call_with_status(CSD_CALL_STATUS_COMING); if (!waiting) waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING); if (!waiting) waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING); active = find_call_with_status(CSD_CALL_STATUS_ACTIVE); if (waiting) err = answer_call(waiting); else if (active) err = release_call(active); else err = 0; if (err < 0) telephony_key_press_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_key_press_rsp(telephony_device, CME_ERROR_NONE); } void telephony_voice_dial_req(void *telephony_device, gboolean enable) { DBG("telephony-maemo6: got %s voice dial request", enable ? "enable" : "disable"); telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED); } static void handle_incoming_call(DBusMessage *msg) { const char *number, *call_path; struct csd_call *call; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &call_path, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) { error("Unexpected parameters in Call.Coming() signal"); return; } call = find_call(call_path); if (!call) { error("Didn't find any matching call object for %s", call_path); return; } DBG("Incoming call to %s from number %s", call_path, number); g_free(call->number); call->number = g_strdup(number); if (find_call_with_status(CSD_CALL_STATUS_ACTIVE) || find_call_with_status(CSD_CALL_STATUS_HOLD)) telephony_call_waiting_ind(call->number, number_type(call->number)); else telephony_incoming_call_ind(call->number, number_type(call->number)); telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_INCOMING); } static void handle_outgoing_call(DBusMessage *msg) { const char *number, *call_path; struct csd_call *call; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &call_path, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) { error("Unexpected parameters in Call.Created() signal"); return; } call = find_call(call_path); if (!call) { error("Didn't find any matching call object for %s", call_path); return; } DBG("Outgoing call from %s to number %s", call_path, number); g_free(call->number); call->number = g_strdup(number); if (create_request_timer) { g_source_remove(create_request_timer); create_request_timer = 0; } } static gboolean create_timeout(gpointer user_data) { telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_INACTIVE); create_request_timer = 0; return FALSE; } static void handle_create_requested(DBusMessage *msg) { DBG("Call.CreateRequested()"); if (create_request_timer) g_source_remove(create_request_timer); create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL); telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_OUTGOING); } static void call_set_status(struct csd_call *call, dbus_uint32_t status) { dbus_uint32_t prev_status; int callheld = telephony_get_indicator(maemo_indicators, "callheld"); prev_status = call->status; DBG("Call %s changed from %s to %s", call->object_path, call_status_str[prev_status], call_status_str[status]); if (prev_status == status) { DBG("Ignoring CSD Call state change to existing state"); return; } call->status = (int) status; switch (status) { case CSD_CALL_STATUS_IDLE: if (call->setup) { telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_INACTIVE); if (!call->originating) telephony_calling_stopped_ind(); } g_free(call->number); call->number = NULL; call->originating = FALSE; call->emergency = FALSE; call->on_hold = FALSE; call->conference = FALSE; call->setup = FALSE; break; case CSD_CALL_STATUS_CREATE: call->originating = TRUE; call->setup = TRUE; break; case CSD_CALL_STATUS_COMING: call->originating = FALSE; call->setup = TRUE; break; case CSD_CALL_STATUS_PROCEEDING: break; case CSD_CALL_STATUS_MO_ALERTING: telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_ALERTING); break; case CSD_CALL_STATUS_MT_ALERTING: /* Some headsets expect incoming call notification before they * can send ATA command. When call changed status from waiting * to alerting we need to send missing notification. Otherwise * headsets like Nokia BH-108 or BackBeat 903 are unable to * answer incoming call that was previously waiting. */ if (prev_status == CSD_CALL_STATUS_WAITING) telephony_incoming_call_ind(call->number, number_type(call->number)); break; case CSD_CALL_STATUS_WAITING: break; case CSD_CALL_STATUS_ANSWERED: break; case CSD_CALL_STATUS_ACTIVE: if (call->on_hold) { call->on_hold = FALSE; if (find_call_with_status(CSD_CALL_STATUS_HOLD)) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_MULTIPLE); else telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_NONE); } else { if (!g_slist_find(active_calls, call)) active_calls = g_slist_prepend(active_calls, call); if (g_slist_length(active_calls) == 1) telephony_update_indicator(maemo_indicators, "call", EV_CALL_ACTIVE); /* Upgrade callheld status if necessary */ if (callheld == EV_CALLHELD_ON_HOLD) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_MULTIPLE); telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_INACTIVE); if (!call->originating) telephony_calling_stopped_ind(); call->setup = FALSE; } break; case CSD_CALL_STATUS_MO_RELEASE: case CSD_CALL_STATUS_MT_RELEASE: active_calls = g_slist_remove(active_calls, call); if (g_slist_length(active_calls) == 0) telephony_update_indicator(maemo_indicators, "call", EV_CALL_INACTIVE); if (create_tones_timer) g_source_remove(create_tones_timer); break; case CSD_CALL_STATUS_HOLD_INITIATED: break; case CSD_CALL_STATUS_HOLD: call->on_hold = TRUE; if (find_non_held_call()) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_MULTIPLE); else telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_ON_HOLD); break; case CSD_CALL_STATUS_RETRIEVE_INITIATED: break; case CSD_CALL_STATUS_RECONNECT_PENDING: break; case CSD_CALL_STATUS_TERMINATED: if (call->on_hold && !find_call_with_status(CSD_CALL_STATUS_HOLD)) { telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_NONE); return; } if (callheld == EV_CALLHELD_MULTIPLE && find_call_with_status(CSD_CALL_STATUS_HOLD) && !find_call_with_status(CSD_CALL_STATUS_ACTIVE)) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_ON_HOLD); break; case CSD_CALL_STATUS_SWAP_INITIATED: break; default: error("Unknown call status %u", status); break; } } static void handle_call_status(DBusMessage *msg, const char *call_path) { struct csd_call *call; dbus_uint32_t status, cause_type, cause; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &status, DBUS_TYPE_UINT32, &cause_type, DBUS_TYPE_UINT32, &cause, DBUS_TYPE_INVALID)) { error("Unexpected parameters in Instance.CallStatus() signal"); return; } call = find_call(call_path); if (!call) { error("Didn't find any matching call object for %s", call_path); return; } if (status > 16) { error("Invalid call status %u", status); return; } call_set_status(call, status); } static void handle_conference(DBusMessage *msg, gboolean joined) { const char *path; struct csd_call *call; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { error("Unexpected parameters in Conference.%s", dbus_message_get_member(msg)); return; } call = find_call(path); if (!call) { error("Conference signal for unknown call %s", path); return; } DBG("Call %s %s the conference", path, joined ? "joined" : "left"); call->conference = joined; } static uint8_t str2status(const char *state) { if (g_strcmp0(state, "Home") == 0) return NETWORK_REG_STATUS_HOME; else if (g_strcmp0(state, "Roaming") == 0) return NETWORK_REG_STATUS_ROAMING; else if (g_strcmp0(state, "Offline") == 0) return NETWORK_REG_STATUS_OFFLINE; else if (g_strcmp0(state, "Searching") == 0) return NETWORK_REG_STATUS_SEARCHING; else if (g_strcmp0(state, "NoSim") == 0) return NETWORK_REG_STATUS_NO_SIM; else if (g_strcmp0(state, "Poweroff") == 0) return NETWORK_REG_STATUS_POWEROFF; else if (g_strcmp0(state, "Powersafe") == 0) return NETWORK_REG_STATUS_POWERSAFE; else if (g_strcmp0(state, "NoCoverage") == 0) return NETWORK_REG_STATUS_NO_COVERAGE; else if (g_strcmp0(state, "Reject") == 0) return NETWORK_REG_STATUS_REJECTED; else return NETWORK_REG_STATUS_UNKOWN; } static void update_registration_status(const char *status) { uint8_t new_status; new_status = str2status(status); if (net.status == new_status) return; switch (new_status) { case NETWORK_REG_STATUS_HOME: telephony_update_indicator(maemo_indicators, "roam", EV_ROAM_INACTIVE); if (net.status > NETWORK_REG_STATUS_ROAMING) telephony_update_indicator(maemo_indicators, "service", EV_SERVICE_PRESENT); break; case NETWORK_REG_STATUS_ROAMING: telephony_update_indicator(maemo_indicators, "roam", EV_ROAM_ACTIVE); if (net.status > NETWORK_REG_STATUS_ROAMING) telephony_update_indicator(maemo_indicators, "service", EV_SERVICE_PRESENT); break; case NETWORK_REG_STATUS_OFFLINE: case NETWORK_REG_STATUS_SEARCHING: case NETWORK_REG_STATUS_NO_SIM: case NETWORK_REG_STATUS_POWEROFF: case NETWORK_REG_STATUS_POWERSAFE: case NETWORK_REG_STATUS_NO_COVERAGE: case NETWORK_REG_STATUS_REJECTED: case NETWORK_REG_STATUS_UNKOWN: if (net.status < NETWORK_REG_STATUS_OFFLINE) telephony_update_indicator(maemo_indicators, "service", EV_SERVICE_NONE); break; } net.status = new_status; DBG("telephony-maemo6: registration status changed: %s", status); } static void handle_registration_changed(DBusMessage *msg) { const char *status; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &status, DBUS_TYPE_INVALID)) { error("Unexpected parameters in RegistrationChanged"); return; } update_registration_status(status); } static void update_signal_strength(int32_t signal_bars) { if (signal_bars < 0) { DBG("signal strength smaller than expected: %d < 0", signal_bars); signal_bars = 0; } else if (signal_bars > 5) { DBG("signal strength greater than expected: %d > 5", signal_bars); signal_bars = 5; } if (net.signal_bars == signal_bars) return; telephony_update_indicator(maemo_indicators, "signal", signal_bars); net.signal_bars = signal_bars; DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars); } static void handle_signal_bars_changed(DBusMessage *msg) { int32_t signal_bars; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INT32, &signal_bars, DBUS_TYPE_INVALID)) { error("Unexpected parameters in SignalBarsChanged"); return; } update_signal_strength(signal_bars); } static gboolean iter_get_basic_args(DBusMessageIter *iter, int first_arg_type, ...) { int type; va_list ap; va_start(ap, first_arg_type); for (type = first_arg_type; type != DBUS_TYPE_INVALID; type = va_arg(ap, int)) { void *value = va_arg(ap, void *); int real_type = dbus_message_iter_get_arg_type(iter); if (real_type != type) { error("iter_get_basic_args: expected %c but got %c", (char) type, (char) real_type); break; } dbus_message_iter_get_basic(iter, value); dbus_message_iter_next(iter); } va_end(ap); return type == DBUS_TYPE_INVALID ? TRUE : FALSE; } static void hal_battery_level_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; dbus_int32_t level; int *value = user_data; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("hald replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } if (!dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32, &level, DBUS_TYPE_INVALID)) { error("Unexpected args in hald reply"); goto done; } *value = (int) level; if (value == &battchg_last) DBG("telephony-maemo6: battery.charge_level.last_full is %d", *value); else if (value == &battchg_design) DBG("telephony-maemo6: battery.charge_level.design is %d", *value); else DBG("telephony-maemo6: battery.charge_level.current is %d", *value); if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) { int new, max; if (battchg_last > 0) max = battchg_last; else max = battchg_design; new = battchg_cur * 5 / max; telephony_update_indicator(maemo_indicators, "battchg", new); } done: dbus_message_unref(reply); remove_pending(call); } static void hal_get_integer(const char *path, const char *key, void *user_data) { send_method_call("org.freedesktop.Hal", path, "org.freedesktop.Hal.Device", "GetPropertyInteger", hal_battery_level_reply, user_data, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID); } static void handle_hal_property_modified(DBusMessage *msg) { DBusMessageIter iter, array; dbus_int32_t num_changes; const char *path; path = dbus_message_get_path(msg); dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) { error("Unexpected signature in hal PropertyModified signal"); return; } dbus_message_iter_get_basic(&iter, &num_changes); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature in hal PropertyModified signal"); return; } dbus_message_iter_recurse(&iter, &array); while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) { DBusMessageIter prop; const char *name; dbus_bool_t added, removed; dbus_message_iter_recurse(&array, &prop); if (!iter_get_basic_args(&prop, DBUS_TYPE_STRING, &name, DBUS_TYPE_BOOLEAN, &added, DBUS_TYPE_BOOLEAN, &removed, DBUS_TYPE_INVALID)) { error("Invalid hal PropertyModified parameters"); break; } if (g_str_equal(name, "battery.charge_level.last_full")) hal_get_integer(path, name, &battchg_last); else if (g_str_equal(name, "battery.charge_level.current")) hal_get_integer(path, name, &battchg_cur); else if (g_str_equal(name, "battery.charge_level.design")) hal_get_integer(path, name, &battchg_design); dbus_message_iter_next(&array); } } static void csd_call_free(void *data) { struct csd_call *call = data; if (!call) return; g_free(call->object_path); g_free(call->number); g_slist_foreach(pending, remove_pending_by_data, call); g_free(call); } static void parse_call_list(DBusMessageIter *iter) { do { DBusMessageIter call_iter; struct csd_call *call; const char *object_path, *number; dbus_uint32_t status; dbus_bool_t originating, terminating, emerg, on_hold, conf; if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) { error("Unexpected signature in GetCallInfoAll reply"); break; } dbus_message_iter_recurse(iter, &call_iter); if (!iter_get_basic_args(&call_iter, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_UINT32, &status, DBUS_TYPE_BOOLEAN, &originating, DBUS_TYPE_BOOLEAN, &terminating, DBUS_TYPE_BOOLEAN, &emerg, DBUS_TYPE_BOOLEAN, &on_hold, DBUS_TYPE_BOOLEAN, &conf, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) { error("Parsing call D-Bus parameters failed"); break; } call = find_call(object_path); if (!call) { call = g_new0(struct csd_call, 1); call->object_path = g_strdup(object_path); calls = g_slist_append(calls, call); DBG("telephony-maemo6: new csd call instance at %s", object_path); } if (status == CSD_CALL_STATUS_IDLE) continue; /* CSD gives incorrect call_hold property sometimes */ if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) || (call->status == CSD_CALL_STATUS_HOLD && !on_hold)) { error("Conflicting call status and on_hold property!"); on_hold = call->status == CSD_CALL_STATUS_HOLD; } call->originating = originating; call->on_hold = on_hold; call->conference = conf; g_free(call->number); call->number = g_strdup(number); /* Update indicators */ call_set_status(call, status); } while (dbus_message_iter_next(iter)); } static void update_operator_name(const char *name) { if (name == NULL) return; g_free(net.operator_name); net.operator_name = g_strndup(name, 16); DBG("telephony-maemo6: operator name updated: %s", name); } static void get_property_reply(DBusPendingCall *call, void *user_data) { char *prop = user_data; DBusError err; DBusMessage *reply; DBusMessageIter iter, sub; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("csd replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) { error("Unexpected signature in Get return"); goto done; } dbus_message_iter_recurse(&iter, &sub); if (g_strcmp0(prop, "RegistrationStatus") == 0) { const char *status; dbus_message_iter_get_basic(&sub, &status); update_registration_status(status); get_property(CSD_CSNET_OPERATOR, "OperatorName"); get_property(CSD_CSNET_SIGNAL, "SignalBars"); } else if (g_strcmp0(prop, "OperatorName") == 0) { const char *name; dbus_message_iter_get_basic(&sub, &name); update_operator_name(name); } else if (g_strcmp0(prop, "SignalBars") == 0) { int32_t signal_bars; dbus_message_iter_get_basic(&sub, &signal_bars); update_signal_strength(signal_bars); } done: g_free(prop); dbus_message_unref(reply); remove_pending(call); } static int get_property(const char *iface, const char *prop) { return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH, DBUS_INTERFACE_PROPERTIES, "Get", get_property_reply, g_strdup(prop), DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &prop, DBUS_TYPE_INVALID); } static void handle_operator_name_changed(DBusMessage *msg) { const char *name; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID)) { error("Unexpected parameters in OperatorNameChanged"); return; } update_operator_name(name); } static void call_info_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; DBusMessageIter iter, sub; get_calls_active = FALSE; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("csd replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature in GetCallInfoAll return"); goto done; } dbus_message_iter_recurse(&iter, &sub); parse_call_list(&sub); get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus"); done: dbus_message_unref(reply); remove_pending(call); } static void phonebook_read_reply(DBusPendingCall *call, void *user_data) { DBusError derr; DBusMessage *reply; const char *name, *number, *secondname, *additionalnumber, *email; int index; char **number_type = user_data; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { error("%s.ReadFirst replied with an error: %s, %s", CSD_SIMPB_INTERFACE, derr.name, derr.message); dbus_error_free(&derr); if (number_type == &vmbx) vmbx = g_strdup(getenv("VMBX_NUMBER")); goto done; } dbus_error_init(&derr); if (dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32, &index, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &number, DBUS_TYPE_STRING, &secondname, DBUS_TYPE_STRING, &additionalnumber, DBUS_TYPE_STRING, &email, DBUS_TYPE_INVALID) == FALSE) { error("Unable to parse %s.ReadFirst arguments: %s, %s", CSD_SIMPB_INTERFACE, derr.name, derr.message); dbus_error_free(&derr); goto done; } if (number_type == &msisdn) { g_free(msisdn); msisdn = g_strdup(number); DBG("Got MSISDN %s (%s)", number, name); } else { g_free(vmbx); vmbx = g_strdup(number); DBG("Got voice mailbox number %s (%s)", number, name); } done: dbus_message_unref(reply); remove_pending(call); } static void csd_init(void) { const char *pb_type; int ret; ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "GetCallInfoAll", call_info_reply, NULL, DBUS_TYPE_INVALID); if (ret < 0) { error("Unable to sent GetCallInfoAll method call"); return; } get_calls_active = TRUE; pb_type = CSD_SIMPB_TYPE_MSISDN; ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH, CSD_SIMPB_INTERFACE, "ReadFirst", phonebook_read_reply, &msisdn, DBUS_TYPE_STRING, &pb_type, DBUS_TYPE_INVALID); if (ret < 0) { error("Unable to send " CSD_SIMPB_INTERFACE ".read()"); return; } /* Voicemail should be in MBDN index 0 */ pb_type = CSD_SIMPB_TYPE_MBDN; ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH, CSD_SIMPB_INTERFACE, "ReadFirst", phonebook_read_reply, &vmbx, DBUS_TYPE_STRING, &pb_type, DBUS_TYPE_INVALID); if (ret < 0) { error("Unable to send " CSD_SIMPB_INTERFACE ".read()"); return; } } static void handle_modem_state(DBusMessage *msg) { const char *state; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state, DBUS_TYPE_INVALID)) { error("Unexpected modem state parameters"); return; } DBG("SSC modem state: %s", state); if (calls != NULL || get_calls_active) return; if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online")) csd_init(); } static void modem_state_reply(DBusPendingCall *call, void *user_data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError err; dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("get_modem_state: %s, %s", err.name, err.message); dbus_error_free(&err); } else handle_modem_state(reply); dbus_message_unref(reply); remove_pending(call); } static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg, void *data) { const char *path = dbus_message_get_path(msg); if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming")) handle_incoming_call(msg); else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created")) handle_outgoing_call(msg); else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "CreateRequested")) handle_create_requested(msg); else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus")) handle_call_status(msg, path); else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined")) handle_conference(msg, TRUE); else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left")) handle_conference(msg, FALSE); else if (dbus_message_is_signal(msg, CSD_CSNET_REGISTRATION, "RegistrationChanged")) handle_registration_changed(msg); else if (dbus_message_is_signal(msg, CSD_CSNET_OPERATOR, "OperatorNameChanged")) handle_operator_name_changed(msg); else if (dbus_message_is_signal(msg, CSD_CSNET_SIGNAL, "SignalBarsChanged")) handle_signal_bars_changed(msg); else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device", "PropertyModified")) handle_hal_property_modified(msg); else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE, "modem_state_changed_ind")) handle_modem_state(msg); return TRUE; } static void add_watch(const char *sender, const char *path, const char *interface, const char *member) { guint watch; watch = g_dbus_add_signal_watch(connection, sender, path, interface, member, signal_filter, NULL, NULL); watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch)); } static void hal_find_device_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; DBusMessageIter iter, sub; const char *path; int type; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("hald replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature in FindDeviceByCapability return"); goto done; } dbus_message_iter_recurse(&iter, &sub); type = dbus_message_iter_get_arg_type(&sub); if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) { error("No hal device with battery capability found"); goto done; } dbus_message_iter_get_basic(&sub, &path); DBG("telephony-maemo6: found battery device at %s", path); add_watch(NULL, path, "org.freedesktop.Hal.Device", "PropertyModified"); hal_get_integer(path, "battery.charge_level.last_full", &battchg_last); hal_get_integer(path, "battery.charge_level.current", &battchg_cur); hal_get_integer(path, "battery.charge_level.design", &battchg_design); done: dbus_message_unref(reply); remove_pending(call); } int telephony_init(void) { const char *battery_cap = "battery"; uint32_t features = AG_FEATURE_EC_ANDOR_NR | AG_FEATURE_INBAND_RINGTONE | AG_FEATURE_REJECT_A_CALL | AG_FEATURE_ENHANCED_CALL_STATUS | AG_FEATURE_ENHANCED_CALL_CONTROL | AG_FEATURE_EXTENDED_ERROR_RESULT_CODES | AG_FEATURE_THREE_WAY_CALLING; int i; DBG(""); connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); add_watch(NULL, NULL, CSD_CALL_INTERFACE, NULL); add_watch(NULL, NULL, CSD_CALL_INSTANCE, NULL); add_watch(NULL, NULL, CSD_CALL_CONFERENCE, NULL); add_watch(NULL, NULL, CSD_CSNET_REGISTRATION, "RegistrationChanged"); add_watch(NULL, NULL, CSD_CSNET_OPERATOR, "OperatorNameChanged"); add_watch(NULL, NULL, CSD_CSNET_SIGNAL, "SignalBarsChanged"); add_watch(NULL, NULL, SSC_DBUS_IFACE, "modem_state_changed_ind"); if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE, "get_modem_state", modem_state_reply, NULL, DBUS_TYPE_INVALID) < 0) error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()"); /* Reset indicators */ for (i = 0; maemo_indicators[i].desc != NULL; i++) { if (g_str_equal(maemo_indicators[i].desc, "battchg")) maemo_indicators[i].val = 5; else maemo_indicators[i].val = 0; } telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED, chld_str); if (send_method_call("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager", "FindDeviceByCapability", hal_find_device_reply, NULL, DBUS_TYPE_STRING, &battery_cap, DBUS_TYPE_INVALID) < 0) error("Unable to send HAL method call"); return 0; } static void remove_watch(gpointer data) { g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data)); } void telephony_exit(void) { DBG(""); g_free(net.operator_name); net.operator_name = NULL; net.status = NETWORK_REG_STATUS_UNKOWN; net.signal_bars = 0; g_slist_free(active_calls); active_calls = NULL; g_slist_free_full(calls, csd_call_free); calls = NULL; g_slist_free_full(pending, pending_req_finalize); pending = NULL; g_slist_free_full(watches, remove_watch); watches = NULL; dbus_connection_unref(connection); connection = NULL; telephony_deinit(); } bluez-4.101/audio/manager.c0000644000000000000000000010051311766125764012425 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "glib-helper.h" #include "btio.h" #include "../src/adapter.h" #include "../src/manager.h" #include "../src/device.h" #include "log.h" #include "ipc.h" #include "device.h" #include "error.h" #include "avdtp.h" #include "media.h" #include "a2dp.h" #include "headset.h" #include "gateway.h" #include "sink.h" #include "source.h" #include "avrcp.h" #include "control.h" #include "manager.h" #include "sdpd.h" #include "telephony.h" #include "unix.h" typedef enum { HEADSET = 1 << 0, GATEWAY = 1 << 1, SINK = 1 << 2, SOURCE = 1 << 3, CONTROL = 1 << 4, TARGET = 1 << 5, INVALID = 1 << 6 } audio_service_type; typedef enum { GENERIC_AUDIO = 0, ADVANCED_AUDIO, AV_REMOTE, GET_RECORDS } audio_sdp_state_t; struct audio_adapter { struct btd_adapter *btd_adapter; gboolean powered; uint32_t hsp_ag_record_id; uint32_t hfp_ag_record_id; uint32_t hfp_hs_record_id; GIOChannel *hsp_ag_server; GIOChannel *hfp_ag_server; GIOChannel *hfp_hs_server; gint ref; }; static gboolean auto_connect = TRUE; static int max_connected_headsets = 1; static DBusConnection *connection = NULL; static GKeyFile *config = NULL; static GSList *adapters = NULL; static GSList *devices = NULL; static struct enabled_interfaces enabled = { .hfp = TRUE, .headset = TRUE, .gateway = FALSE, .sink = TRUE, .source = FALSE, .control = TRUE, .socket = FALSE, .media = TRUE, }; static struct audio_adapter *find_adapter(GSList *list, struct btd_adapter *btd_adapter) { for (; list; list = list->next) { struct audio_adapter *adapter = list->data; if (adapter->btd_adapter == btd_adapter) return adapter; } return NULL; } gboolean server_is_enabled(bdaddr_t *src, uint16_t svc) { switch (svc) { case HEADSET_SVCLASS_ID: return enabled.headset; case HEADSET_AGW_SVCLASS_ID: return FALSE; case HANDSFREE_SVCLASS_ID: return enabled.headset && enabled.hfp; case HANDSFREE_AGW_SVCLASS_ID: return enabled.gateway; case AUDIO_SINK_SVCLASS_ID: return enabled.sink; case AUDIO_SOURCE_SVCLASS_ID: return enabled.source; case AV_REMOTE_TARGET_SVCLASS_ID: case AV_REMOTE_SVCLASS_ID: return enabled.control; default: return FALSE; } } static void handle_uuid(const char *uuidstr, struct audio_device *device) { uuid_t uuid; uint16_t uuid16; if (bt_string2uuid(&uuid, uuidstr) < 0) { error("%s not detected as an UUID-128", uuidstr); return; } if (!sdp_uuid128_to_uuid(&uuid) && uuid.type != SDP_UUID16) { error("Could not convert %s to a UUID-16", uuidstr); return; } uuid16 = uuid.value.uuid16; if (!server_is_enabled(&device->src, uuid16)) { DBG("server not enabled for %s (0x%04x)", uuidstr, uuid16); return; } switch (uuid16) { case HEADSET_SVCLASS_ID: DBG("Found Headset record"); if (device->headset) headset_update(device, uuid16, uuidstr); else device->headset = headset_init(device, uuid16, uuidstr); break; case HEADSET_AGW_SVCLASS_ID: DBG("Found Headset AG record"); break; case HANDSFREE_SVCLASS_ID: DBG("Found Handsfree record"); if (device->headset) headset_update(device, uuid16, uuidstr); else device->headset = headset_init(device, uuid16, uuidstr); break; case HANDSFREE_AGW_SVCLASS_ID: DBG("Found Handsfree AG record"); if (enabled.gateway && (device->gateway == NULL)) device->gateway = gateway_init(device); break; case AUDIO_SINK_SVCLASS_ID: DBG("Found Audio Sink"); if (device->sink == NULL) device->sink = sink_init(device); break; case AUDIO_SOURCE_SVCLASS_ID: DBG("Found Audio Source"); if (device->source == NULL) device->source = source_init(device); break; case AV_REMOTE_SVCLASS_ID: case AV_REMOTE_TARGET_SVCLASS_ID: DBG("Found AV %s", uuid16 == AV_REMOTE_SVCLASS_ID ? "Remote" : "Target"); if (device->control) control_update(device->control, uuid16); else device->control = control_init(device, uuid16); if (device->sink && sink_is_active(device)) avrcp_connect(device); break; default: DBG("Unrecognized UUID: 0x%04X", uuid16); break; } } static sdp_record_t *hsp_ag_record(uint8_t ch) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, svclass_uuid, ga_svclass_uuid; uuid_t l2cap_uuid, rfcomm_uuid; sdp_profile_desc_t profile; sdp_record_t *record; sdp_list_t *aproto, *proto[2]; sdp_data_t *channel; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID); svclass_id = sdp_list_append(0, &svclass_uuid); sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID); profile.version = 0x0102; pfseq = sdp_list_append(0, &profile); sdp_set_profile_descs(record, pfseq); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap_uuid); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); proto[1] = sdp_list_append(0, &rfcomm_uuid); channel = sdp_data_alloc(SDP_UINT8, &ch); proto[1] = sdp_list_append(proto[1], channel); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(record, aproto); sdp_set_info_attr(record, "Headset Audio Gateway", 0, 0); sdp_data_free(channel); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(pfseq, 0); sdp_list_free(aproto, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); return record; } static sdp_record_t *hfp_hs_record(uint8_t ch) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, svclass_uuid, ga_svclass_uuid; uuid_t l2cap_uuid, rfcomm_uuid; sdp_profile_desc_t profile; sdp_record_t *record; sdp_list_t *aproto, *proto[2]; sdp_data_t *channel; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID); svclass_id = sdp_list_append(0, &svclass_uuid); sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID); profile.version = 0x0105; pfseq = sdp_list_append(0, &profile); sdp_set_profile_descs(record, pfseq); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap_uuid); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); proto[1] = sdp_list_append(0, &rfcomm_uuid); channel = sdp_data_alloc(SDP_UINT8, &ch); proto[1] = sdp_list_append(proto[1], channel); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(record, aproto); sdp_set_info_attr(record, "Hands-Free", 0, 0); sdp_data_free(channel); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(pfseq, 0); sdp_list_free(aproto, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); return record; } static sdp_record_t *hfp_ag_record(uint8_t ch, uint32_t feat) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, svclass_uuid, ga_svclass_uuid; uuid_t l2cap_uuid, rfcomm_uuid; sdp_profile_desc_t profile; sdp_list_t *aproto, *proto[2]; sdp_record_t *record; sdp_data_t *channel, *features; uint8_t netid = 0x01; uint16_t sdpfeat; sdp_data_t *network; record = sdp_record_alloc(); if (!record) return NULL; network = sdp_data_alloc(SDP_UINT8, &netid); if (!network) { sdp_record_free(record); return NULL; } sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(0, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID); svclass_id = sdp_list_append(0, &svclass_uuid); sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID); svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID); profile.version = 0x0105; pfseq = sdp_list_append(0, &profile); sdp_set_profile_descs(record, pfseq); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(0, &l2cap_uuid); apseq = sdp_list_append(0, proto[0]); sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); proto[1] = sdp_list_append(0, &rfcomm_uuid); channel = sdp_data_alloc(SDP_UINT8, &ch); proto[1] = sdp_list_append(proto[1], channel); apseq = sdp_list_append(apseq, proto[1]); sdpfeat = (uint16_t) feat & 0xF; features = sdp_data_alloc(SDP_UINT16, &sdpfeat); sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features); aproto = sdp_list_append(0, apseq); sdp_set_access_protos(record, aproto); sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0); sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network); sdp_data_free(channel); sdp_list_free(proto[0], 0); sdp_list_free(proto[1], 0); sdp_list_free(apseq, 0); sdp_list_free(pfseq, 0); sdp_list_free(aproto, 0); sdp_list_free(root, 0); sdp_list_free(svclass_id, 0); return record; } static void headset_auth_cb(DBusError *derr, void *user_data) { struct audio_device *device = user_data; GError *err = NULL; GIOChannel *io; if (device->hs_preauth_id) { g_source_remove(device->hs_preauth_id); device->hs_preauth_id = 0; } if (derr && dbus_error_is_set(derr)) { error("Access denied: %s", derr->message); headset_set_state(device, HEADSET_STATE_DISCONNECTED); return; } io = headset_get_rfcomm(device); if (!bt_io_accept(io, headset_connect_cb, device, NULL, &err)) { error("bt_io_accept: %s", err->message); g_error_free(err); headset_set_state(device, HEADSET_STATE_DISCONNECTED); return; } } static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data) { struct audio_device *device = user_data; DBG("Headset disconnected during authorization"); audio_device_cancel_authorization(device, headset_auth_cb, device); headset_set_state(device, HEADSET_STATE_DISCONNECTED); device->hs_preauth_id = 0; return FALSE; } static void ag_confirm(GIOChannel *chan, gpointer data) { const char *server_uuid, *remote_uuid; struct audio_device *device; gboolean hfp_active; bdaddr_t src, dst; int perr; GError *err = NULL; uint8_t ch; bt_io_get(chan, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_CHANNEL, &ch, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } if (ch == DEFAULT_HS_AG_CHANNEL) { hfp_active = FALSE; server_uuid = HSP_AG_UUID; remote_uuid = HSP_HS_UUID; } else { hfp_active = TRUE; server_uuid = HFP_AG_UUID; remote_uuid = HFP_HS_UUID; } device = manager_get_device(&src, &dst, TRUE); if (!device) goto drop; if (!manager_allow_headset_connection(device)) { DBG("Refusing headset: too many existing connections"); goto drop; } if (!device->headset) { btd_device_add_uuid(device->btd_dev, remote_uuid); if (!device->headset) goto drop; } if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) { DBG("Refusing new connection since one already exists"); goto drop; } headset_set_hfp_active(device, hfp_active); headset_set_rfcomm_initiator(device, TRUE); if (headset_connect_rfcomm(device, chan) < 0) { error("headset_connect_rfcomm failed"); goto drop; } headset_set_state(device, HEADSET_STATE_CONNECTING); perr = audio_device_request_authorization(device, server_uuid, headset_auth_cb, device); if (perr < 0) { DBG("Authorization denied: %s", strerror(-perr)); headset_set_state(device, HEADSET_STATE_DISCONNECTED); return; } device->hs_preauth_id = g_io_add_watch(chan, G_IO_NVAL | G_IO_HUP | G_IO_ERR, hs_preauth_cb, device); device->auto_connect = auto_connect; return; drop: g_io_channel_shutdown(chan, TRUE, NULL); } static void gateway_auth_cb(DBusError *derr, void *user_data) { struct audio_device *device = user_data; if (derr && dbus_error_is_set(derr)) { error("Access denied: %s", derr->message); gateway_set_state(device, GATEWAY_STATE_DISCONNECTED); } else { char ag_address[18]; ba2str(&device->dst, ag_address); DBG("Accepted AG connection from %s for %s", ag_address, device->path); gateway_start_service(device); } } static void hf_io_cb(GIOChannel *chan, gpointer data) { bdaddr_t src, dst; GError *err = NULL; uint8_t ch; const char *server_uuid, *remote_uuid; struct audio_device *device; int perr; bt_io_get(chan, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_CHANNEL, &ch, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); return; } server_uuid = HFP_HS_UUID; remote_uuid = HFP_AG_UUID; device = manager_get_device(&src, &dst, TRUE); if (!device) goto drop; if (!device->gateway) { btd_device_add_uuid(device->btd_dev, remote_uuid); if (!device->gateway) goto drop; } if (gateway_is_active(device)) { DBG("Refusing new connection since one already exists"); goto drop; } if (gateway_connect_rfcomm(device, chan) < 0) { error("Allocating new GIOChannel failed!"); goto drop; } perr = audio_device_request_authorization(device, server_uuid, gateway_auth_cb, device); if (perr < 0) { DBG("Authorization denied: %s", strerror(-perr)); gateway_set_state(device, GATEWAY_STATE_DISCONNECTED); } return; drop: g_io_channel_shutdown(chan, TRUE, NULL); } static int headset_server_init(struct audio_adapter *adapter) { uint8_t chan = DEFAULT_HS_AG_CHANNEL; sdp_record_t *record; gboolean master = TRUE; GError *err = NULL; uint32_t features; GIOChannel *io; bdaddr_t src; if (config) { gboolean tmp; tmp = g_key_file_get_boolean(config, "General", "Master", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else master = tmp; } adapter_get_address(adapter->btd_adapter, &src); io = bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, adapter, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_CHANNEL, chan, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_MASTER, master, BT_IO_OPT_INVALID); if (!io) goto failed; adapter->hsp_ag_server = io; record = hsp_ag_record(chan); if (!record) { error("Unable to allocate new service record"); goto failed; } if (add_record_to_server(&src, record) < 0) { error("Unable to register HS AG service record"); sdp_record_free(record); goto failed; } adapter->hsp_ag_record_id = record->handle; features = headset_config_init(config); if (!enabled.hfp) return 0; chan = DEFAULT_HF_AG_CHANNEL; io = bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, adapter, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_CHANNEL, chan, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_MASTER, master, BT_IO_OPT_INVALID); if (!io) goto failed; adapter->hfp_ag_server = io; record = hfp_ag_record(chan, features); if (!record) { error("Unable to allocate new service record"); goto failed; } if (add_record_to_server(&src, record) < 0) { error("Unable to register HF AG service record"); sdp_record_free(record); goto failed; } adapter->hfp_ag_record_id = record->handle; return 0; failed: if (err) { error("%s", err->message); g_error_free(err); } if (adapter->hsp_ag_server) { g_io_channel_shutdown(adapter->hsp_ag_server, TRUE, NULL); g_io_channel_unref(adapter->hsp_ag_server); adapter->hsp_ag_server = NULL; } if (adapter->hfp_ag_server) { g_io_channel_shutdown(adapter->hfp_ag_server, TRUE, NULL); g_io_channel_unref(adapter->hfp_ag_server); adapter->hfp_ag_server = NULL; } return -1; } static int gateway_server_init(struct audio_adapter *adapter) { uint8_t chan = DEFAULT_HFP_HS_CHANNEL; sdp_record_t *record; gboolean master = TRUE; GError *err = NULL; GIOChannel *io; bdaddr_t src; if (config) { gboolean tmp; tmp = g_key_file_get_boolean(config, "General", "Master", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else master = tmp; } adapter_get_address(adapter->btd_adapter, &src); io = bt_io_listen(BT_IO_RFCOMM, NULL, hf_io_cb, adapter, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_CHANNEL, chan, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_MASTER, master, BT_IO_OPT_INVALID); if (!io) { error("%s", err->message); g_error_free(err); return -1; } adapter->hfp_hs_server = io; record = hfp_hs_record(chan); if (!record) { error("Unable to allocate new service record"); goto failed; } if (add_record_to_server(&src, record) < 0) { error("Unable to register HFP HS service record"); sdp_record_free(record); goto failed; } adapter->hfp_hs_record_id = record->handle; return 0; failed: g_io_channel_shutdown(adapter->hfp_hs_server, TRUE, NULL); g_io_channel_unref(adapter->hfp_hs_server); adapter->hfp_hs_server = NULL; return -1; } static int audio_probe(struct btd_device *device, GSList *uuids) { struct btd_adapter *adapter = device_get_adapter(device); bdaddr_t src, dst; struct audio_device *audio_dev; adapter_get_address(adapter, &src); device_get_address(device, &dst, NULL); audio_dev = manager_get_device(&src, &dst, TRUE); if (!audio_dev) { DBG("unable to get a device object"); return -1; } g_slist_foreach(uuids, (GFunc) handle_uuid, audio_dev); return 0; } static void audio_remove(struct btd_device *device) { struct audio_device *dev; const char *path; path = device_get_path(device); dev = manager_find_device(path, NULL, NULL, NULL, FALSE); if (!dev) return; devices = g_slist_remove(devices, dev); audio_device_unregister(dev); } static struct audio_adapter *audio_adapter_ref(struct audio_adapter *adp) { adp->ref++; DBG("%p: ref=%d", adp, adp->ref); return adp; } static void audio_adapter_unref(struct audio_adapter *adp) { adp->ref--; DBG("%p: ref=%d", adp, adp->ref); if (adp->ref > 0) return; adapters = g_slist_remove(adapters, adp); btd_adapter_unref(adp->btd_adapter); g_free(adp); } static struct audio_adapter *audio_adapter_create(struct btd_adapter *adapter) { struct audio_adapter *adp; adp = g_new0(struct audio_adapter, 1); adp->btd_adapter = btd_adapter_ref(adapter); return audio_adapter_ref(adp); } static struct audio_adapter *audio_adapter_get(struct btd_adapter *adapter) { struct audio_adapter *adp; adp = find_adapter(adapters, adapter); if (!adp) { adp = audio_adapter_create(adapter); adapters = g_slist_append(adapters, adp); } else audio_adapter_ref(adp); return adp; } static void state_changed(struct btd_adapter *adapter, gboolean powered) { struct audio_adapter *adp; static gboolean telephony = FALSE; GSList *l; DBG("%s powered %s", adapter_get_path(adapter), powered ? "on" : "off"); /* ignore powered change, adapter is powering down */ if (powered && adapter_powering_down(adapter)) return; adp = find_adapter(adapters, adapter); if (!adp) return; adp->powered = powered; if (powered) { /* telephony driver already initialized*/ if (telephony == TRUE) return; telephony_init(); telephony = TRUE; return; } /* telephony not initialized just ignore power down */ if (telephony == FALSE) return; for (l = adapters; l; l = l->next) { adp = l->data; if (adp->powered == TRUE) return; } telephony_exit(); telephony = FALSE; } static int headset_server_probe(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); int err; DBG("path %s", path); adp = audio_adapter_get(adapter); if (!adp) return -EINVAL; err = headset_server_init(adp); if (err < 0) { audio_adapter_unref(adp); return err; } btd_adapter_register_powered_callback(adapter, state_changed); return 0; } static void headset_server_remove(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); DBG("path %s", path); btd_adapter_unregister_powered_callback(adapter, state_changed); adp = find_adapter(adapters, adapter); if (!adp) return; if (adp->hsp_ag_record_id) { remove_record_from_server(adp->hsp_ag_record_id); adp->hsp_ag_record_id = 0; } if (adp->hsp_ag_server) { g_io_channel_shutdown(adp->hsp_ag_server, TRUE, NULL); g_io_channel_unref(adp->hsp_ag_server); adp->hsp_ag_server = NULL; } if (adp->hfp_ag_record_id) { remove_record_from_server(adp->hfp_ag_record_id); adp->hfp_ag_record_id = 0; } if (adp->hfp_ag_server) { g_io_channel_shutdown(adp->hfp_ag_server, TRUE, NULL); g_io_channel_unref(adp->hfp_ag_server); adp->hfp_ag_server = NULL; } audio_adapter_unref(adp); } static int gateway_server_probe(struct btd_adapter *adapter) { struct audio_adapter *adp; int err; adp = audio_adapter_get(adapter); if (!adp) return -EINVAL; err = gateway_server_init(adp); if (err < 0) audio_adapter_unref(adp); return err; } static void gateway_server_remove(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); DBG("path %s", path); adp = find_adapter(adapters, adapter); if (!adp) return; if (adp->hfp_hs_record_id) { remove_record_from_server(adp->hfp_hs_record_id); adp->hfp_hs_record_id = 0; } if (adp->hfp_hs_server) { g_io_channel_shutdown(adp->hfp_hs_server, TRUE, NULL); g_io_channel_unref(adp->hfp_hs_server); adp->hfp_hs_server = NULL; } audio_adapter_unref(adp); } static int a2dp_server_probe(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); bdaddr_t src; int err; DBG("path %s", path); adp = audio_adapter_get(adapter); if (!adp) return -EINVAL; adapter_get_address(adapter, &src); err = a2dp_register(connection, &src, config); if (err < 0) audio_adapter_unref(adp); return err; } static void a2dp_server_remove(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); bdaddr_t src; DBG("path %s", path); adp = find_adapter(adapters, adapter); if (!adp) return; adapter_get_address(adapter, &src); a2dp_unregister(&src); audio_adapter_unref(adp); } static int avrcp_server_probe(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); bdaddr_t src; int err; DBG("path %s", path); adp = audio_adapter_get(adapter); if (!adp) return -EINVAL; adapter_get_address(adapter, &src); err = avrcp_register(connection, &src, config); if (err < 0) audio_adapter_unref(adp); return err; } static void avrcp_server_remove(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); bdaddr_t src; DBG("path %s", path); adp = find_adapter(adapters, adapter); if (!adp) return; adapter_get_address(adapter, &src); avrcp_unregister(&src); audio_adapter_unref(adp); } static int media_server_probe(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); bdaddr_t src; int err; DBG("path %s", path); adp = audio_adapter_get(adapter); if (!adp) return -EINVAL; adapter_get_address(adapter, &src); err = media_register(connection, path, &src); if (err < 0) audio_adapter_unref(adp); return err; } static void media_server_remove(struct btd_adapter *adapter) { struct audio_adapter *adp; const gchar *path = adapter_get_path(adapter); DBG("path %s", path); adp = find_adapter(adapters, adapter); if (!adp) return; media_unregister(path); audio_adapter_unref(adp); } static struct btd_device_driver audio_driver = { .name = "audio", .uuids = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID, ADVANCED_AUDIO_UUID, A2DP_SOURCE_UUID, A2DP_SINK_UUID, AVRCP_TARGET_UUID, AVRCP_REMOTE_UUID), .probe = audio_probe, .remove = audio_remove, }; static struct btd_adapter_driver headset_server_driver = { .name = "audio-headset", .probe = headset_server_probe, .remove = headset_server_remove, }; static struct btd_adapter_driver gateway_server_driver = { .name = "audio-gateway", .probe = gateway_server_probe, .remove = gateway_server_remove, }; static struct btd_adapter_driver a2dp_server_driver = { .name = "audio-a2dp", .probe = a2dp_server_probe, .remove = a2dp_server_remove, }; static struct btd_adapter_driver avrcp_server_driver = { .name = "audio-control", .probe = avrcp_server_probe, .remove = avrcp_server_remove, }; static struct btd_adapter_driver media_server_driver = { .name = "media", .probe = media_server_probe, .remove = media_server_remove, }; int audio_manager_init(DBusConnection *conn, GKeyFile *conf, gboolean *enable_sco) { char **list; int i; gboolean b; GError *err = NULL; connection = dbus_connection_ref(conn); if (!conf) goto proceed; config = conf; list = g_key_file_get_string_list(config, "General", "Enable", NULL, NULL); for (i = 0; list && list[i] != NULL; i++) { if (g_str_equal(list[i], "Headset")) enabled.headset = TRUE; else if (g_str_equal(list[i], "Gateway")) enabled.gateway = TRUE; else if (g_str_equal(list[i], "Sink")) enabled.sink = TRUE; else if (g_str_equal(list[i], "Source")) enabled.source = TRUE; else if (g_str_equal(list[i], "Control")) enabled.control = TRUE; else if (g_str_equal(list[i], "Socket")) enabled.socket = TRUE; else if (g_str_equal(list[i], "Media")) enabled.media = TRUE; } g_strfreev(list); list = g_key_file_get_string_list(config, "General", "Disable", NULL, NULL); for (i = 0; list && list[i] != NULL; i++) { if (g_str_equal(list[i], "Headset")) enabled.headset = FALSE; else if (g_str_equal(list[i], "Gateway")) enabled.gateway = FALSE; else if (g_str_equal(list[i], "Sink")) enabled.sink = FALSE; else if (g_str_equal(list[i], "Source")) enabled.source = FALSE; else if (g_str_equal(list[i], "Control")) enabled.control = FALSE; else if (g_str_equal(list[i], "Socket")) enabled.socket = FALSE; else if (g_str_equal(list[i], "Media")) enabled.media = FALSE; } g_strfreev(list); b = g_key_file_get_boolean(config, "General", "AutoConnect", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else auto_connect = b; b = g_key_file_get_boolean(config, "Headset", "HFP", &err); if (err) g_clear_error(&err); else enabled.hfp = b; err = NULL; i = g_key_file_get_integer(config, "Headset", "MaxConnected", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else max_connected_headsets = i; proceed: if (enabled.socket) unix_init(); if (enabled.media) btd_register_adapter_driver(&media_server_driver); if (enabled.headset) btd_register_adapter_driver(&headset_server_driver); if (enabled.gateway) btd_register_adapter_driver(&gateway_server_driver); if (enabled.source || enabled.sink) btd_register_adapter_driver(&a2dp_server_driver); if (enabled.control) btd_register_adapter_driver(&avrcp_server_driver); btd_register_device_driver(&audio_driver); *enable_sco = (enabled.gateway || enabled.headset); return 0; } void audio_manager_exit(void) { /* Bail out early if we haven't been initialized */ if (connection == NULL) return; dbus_connection_unref(connection); connection = NULL; if (config) { g_key_file_free(config); config = NULL; } if (enabled.socket) unix_exit(); if (enabled.media) btd_unregister_adapter_driver(&media_server_driver); if (enabled.headset) btd_unregister_adapter_driver(&headset_server_driver); if (enabled.gateway) btd_unregister_adapter_driver(&gateway_server_driver); if (enabled.source || enabled.sink) btd_unregister_adapter_driver(&a2dp_server_driver); if (enabled.control) btd_unregister_adapter_driver(&avrcp_server_driver); btd_unregister_device_driver(&audio_driver); } GSList *manager_find_devices(const char *path, const bdaddr_t *src, const bdaddr_t *dst, const char *interface, gboolean connected) { GSList *result = NULL; GSList *l; for (l = devices; l != NULL; l = l->next) { struct audio_device *dev = l->data; if ((path && (strcmp(path, "")) && strcmp(dev->path, path))) continue; if ((src && bacmp(src, BDADDR_ANY)) && bacmp(&dev->src, src)) continue; if ((dst && bacmp(dst, BDADDR_ANY)) && bacmp(&dev->dst, dst)) continue; if (interface && !strcmp(AUDIO_HEADSET_INTERFACE, interface) && !dev->headset) continue; if (interface && !strcmp(AUDIO_GATEWAY_INTERFACE, interface) && !dev->gateway) continue; if (interface && !strcmp(AUDIO_SINK_INTERFACE, interface) && !dev->sink) continue; if (interface && !strcmp(AUDIO_SOURCE_INTERFACE, interface) && !dev->source) continue; if (interface && !strcmp(AUDIO_CONTROL_INTERFACE, interface) && !dev->control) continue; if (connected && !audio_device_is_active(dev, interface)) continue; result = g_slist_append(result, dev); } return result; } struct audio_device *manager_find_device(const char *path, const bdaddr_t *src, const bdaddr_t *dst, const char *interface, gboolean connected) { struct audio_device *result; GSList *l; l = manager_find_devices(path, src, dst, interface, connected); if (l == NULL) return NULL; result = l->data; g_slist_free(l); return result; } struct audio_device *manager_get_device(const bdaddr_t *src, const bdaddr_t *dst, gboolean create) { struct audio_device *dev; struct btd_adapter *adapter; struct btd_device *device; char addr[18]; const char *path; dev = manager_find_device(NULL, src, dst, NULL, FALSE); if (dev) return dev; if (!create) return NULL; ba2str(src, addr); adapter = manager_find_adapter(src); if (!adapter) { error("Unable to get a btd_adapter object for %s", addr); return NULL; } ba2str(dst, addr); device = adapter_get_device(connection, adapter, addr); if (!device) { error("Unable to get btd_device object for %s", addr); return NULL; } path = device_get_path(device); dev = audio_device_register(connection, device, path, src, dst); if (!dev) return NULL; devices = g_slist_append(devices, dev); return dev; } gboolean manager_allow_headset_connection(struct audio_device *device) { GSList *l; int connected = 0; for (l = devices; l != NULL; l = l->next) { struct audio_device *dev = l->data; struct headset *hs = dev->headset; if (dev == device) continue; if (device && bacmp(&dev->src, &device->src) != 0) continue; if (!hs) continue; if (headset_get_state(dev) > HEADSET_STATE_DISCONNECTED) connected++; if (connected >= max_connected_headsets) return FALSE; } return TRUE; } void manager_set_fast_connectable(gboolean enable) { GSList *l; if (enable && !manager_allow_headset_connection(NULL)) { DBG("Refusing enabling fast connectable"); return; } for (l = adapters; l != NULL; l = l->next) { struct audio_adapter *adapter = l->data; if (btd_adapter_set_fast_connectable(adapter->btd_adapter, enable)) error("Changing fast connectable for hci%d failed", adapter_get_dev_id(adapter->btd_adapter)); } } bluez-4.101/audio/gstrtpsbcpay.c0000644000000000000000000002327111766125764013545 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include "gstpragma.h" #include "gstrtpsbcpay.h" #include #include #define RTP_SBC_PAYLOAD_HEADER_SIZE 1 #define DEFAULT_MIN_FRAMES 0 #define RTP_SBC_HEADER_TOTAL (12 + RTP_SBC_PAYLOAD_HEADER_SIZE) #if __BYTE_ORDER == __LITTLE_ENDIAN struct rtp_payload { guint8 frame_count:4; guint8 rfa0:1; guint8 is_last_fragment:1; guint8 is_first_fragment:1; guint8 is_fragmented:1; } __attribute__ ((packed)); #elif __BYTE_ORDER == __BIG_ENDIAN struct rtp_payload { guint8 is_fragmented:1; guint8 is_first_fragment:1; guint8 is_last_fragment:1; guint8 rfa0:1; guint8 frame_count:4; } __attribute__ ((packed)); #else #error "Unknown byte order" #endif enum { PROP_0, PROP_MIN_FRAMES }; GST_DEBUG_CATEGORY_STATIC(gst_rtp_sbc_pay_debug); #define GST_CAT_DEFAULT gst_rtp_sbc_pay_debug GST_BOILERPLATE(GstRtpSBCPay, gst_rtp_sbc_pay, GstBaseRTPPayload, GST_TYPE_BASE_RTP_PAYLOAD); static const GstElementDetails gst_rtp_sbc_pay_details = GST_ELEMENT_DETAILS("RTP packet payloader", "Codec/Payloader/Network", "Payload SBC audio as RTP packets", "Thiago Sousa Santos " ""); static GstStaticPadTemplate gst_rtp_sbc_pay_sink_factory = GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS, GST_STATIC_CAPS("audio/x-sbc, " "rate = (int) { 16000, 32000, 44100, 48000 }, " "channels = (int) [ 1, 2 ], " "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, " "blocks = (int) { 4, 8, 12, 16 }, " "subbands = (int) { 4, 8 }, " "allocation = (string) { \"snr\", \"loudness\" }, " "bitpool = (int) [ 2, 64 ]") ); static GstStaticPadTemplate gst_rtp_sbc_pay_src_factory = GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS, GST_STATIC_CAPS( "application/x-rtp, " "media = (string) \"audio\"," "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", " "clock-rate = (int) { 16000, 32000, 44100, 48000 }," "encoding-name = (string) \"SBC\"") ); static void gst_rtp_sbc_pay_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void gst_rtp_sbc_pay_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static gint gst_rtp_sbc_pay_get_frame_len(gint subbands, gint channels, gint blocks, gint bitpool, const gchar *channel_mode) { gint len; gint join; len = 4 + (4 * subbands * channels)/8; if (strcmp(channel_mode, "mono") == 0 || strcmp(channel_mode, "dual") == 0) len += ((blocks * channels * bitpool) + 7) / 8; else { join = strcmp(channel_mode, "joint") == 0 ? 1 : 0; len += ((join * subbands + blocks * bitpool) + 7) / 8; } return len; } static gboolean gst_rtp_sbc_pay_set_caps(GstBaseRTPPayload *payload, GstCaps *caps) { GstRtpSBCPay *sbcpay; gint rate, subbands, channels, blocks, bitpool; gint frame_len; const gchar *channel_mode; GstStructure *structure; sbcpay = GST_RTP_SBC_PAY(payload); structure = gst_caps_get_structure(caps, 0); if (!gst_structure_get_int(structure, "rate", &rate)) return FALSE; if (!gst_structure_get_int(structure, "channels", &channels)) return FALSE; if (!gst_structure_get_int(structure, "blocks", &blocks)) return FALSE; if (!gst_structure_get_int(structure, "bitpool", &bitpool)) return FALSE; if (!gst_structure_get_int(structure, "subbands", &subbands)) return FALSE; channel_mode = gst_structure_get_string(structure, "mode"); if (!channel_mode) return FALSE; frame_len = gst_rtp_sbc_pay_get_frame_len(subbands, channels, blocks, bitpool, channel_mode); sbcpay->frame_length = frame_len; gst_basertppayload_set_options(payload, "audio", TRUE, "SBC", rate); GST_DEBUG_OBJECT(payload, "calculated frame length: %d ", frame_len); return gst_basertppayload_set_outcaps(payload, NULL); } static GstFlowReturn gst_rtp_sbc_pay_flush_buffers(GstRtpSBCPay *sbcpay) { guint available; guint max_payload; GstBuffer *outbuf; guint8 *payload_data; guint frame_count; guint payload_length; struct rtp_payload *payload; if (sbcpay->frame_length == 0) { GST_ERROR_OBJECT(sbcpay, "Frame length is 0"); return GST_FLOW_ERROR; } available = gst_adapter_available(sbcpay->adapter); max_payload = gst_rtp_buffer_calc_payload_len( GST_BASE_RTP_PAYLOAD_MTU(sbcpay) - RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); max_payload = MIN(max_payload, available); frame_count = max_payload / sbcpay->frame_length; payload_length = frame_count * sbcpay->frame_length; if (payload_length == 0) /* Nothing to send */ return GST_FLOW_OK; outbuf = gst_rtp_buffer_new_allocate(payload_length + RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0); gst_rtp_buffer_set_payload_type(outbuf, GST_BASE_RTP_PAYLOAD_PT(sbcpay)); payload_data = gst_rtp_buffer_get_payload(outbuf); payload = (struct rtp_payload *) payload_data; memset(payload, 0, sizeof(struct rtp_payload)); payload->frame_count = frame_count; gst_adapter_copy(sbcpay->adapter, payload_data + RTP_SBC_PAYLOAD_HEADER_SIZE, 0, payload_length); gst_adapter_flush(sbcpay->adapter, payload_length); GST_BUFFER_TIMESTAMP(outbuf) = sbcpay->timestamp; GST_DEBUG_OBJECT(sbcpay, "Pushing %d bytes", payload_length); return gst_basertppayload_push(GST_BASE_RTP_PAYLOAD(sbcpay), outbuf); } static GstFlowReturn gst_rtp_sbc_pay_handle_buffer(GstBaseRTPPayload *payload, GstBuffer *buffer) { GstRtpSBCPay *sbcpay; guint available; /* FIXME check for negotiation */ sbcpay = GST_RTP_SBC_PAY(payload); sbcpay->timestamp = GST_BUFFER_TIMESTAMP(buffer); gst_adapter_push(sbcpay->adapter, buffer); available = gst_adapter_available(sbcpay->adapter); if (available + RTP_SBC_HEADER_TOTAL >= GST_BASE_RTP_PAYLOAD_MTU(sbcpay) || (available > (sbcpay->min_frames * sbcpay->frame_length))) return gst_rtp_sbc_pay_flush_buffers(sbcpay); return GST_FLOW_OK; } static gboolean gst_rtp_sbc_pay_handle_event(GstPad *pad, GstEvent *event) { GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY(GST_PAD_PARENT(pad)); switch (GST_EVENT_TYPE(event)) { case GST_EVENT_EOS: gst_rtp_sbc_pay_flush_buffers(sbcpay); break; default: break; } return FALSE; } static void gst_rtp_sbc_pay_base_init(gpointer g_class) { GstElementClass *element_class = GST_ELEMENT_CLASS(g_class); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&gst_rtp_sbc_pay_sink_factory)); gst_element_class_add_pad_template(element_class, gst_static_pad_template_get(&gst_rtp_sbc_pay_src_factory)); gst_element_class_set_details(element_class, &gst_rtp_sbc_pay_details); } static void gst_rtp_sbc_pay_finalize(GObject *object) { GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY(object); g_object_unref(sbcpay->adapter); GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object)); } static void gst_rtp_sbc_pay_class_init(GstRtpSBCPayClass *klass) { GObjectClass *gobject_class; GstBaseRTPPayloadClass *payload_class = GST_BASE_RTP_PAYLOAD_CLASS(klass); gobject_class = G_OBJECT_CLASS(klass); parent_class = g_type_class_peek_parent(klass); gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_rtp_sbc_pay_finalize); gobject_class->set_property = GST_DEBUG_FUNCPTR( gst_rtp_sbc_pay_set_property); gobject_class->get_property = GST_DEBUG_FUNCPTR( gst_rtp_sbc_pay_get_property); payload_class->set_caps = GST_DEBUG_FUNCPTR(gst_rtp_sbc_pay_set_caps); payload_class->handle_buffer = GST_DEBUG_FUNCPTR( gst_rtp_sbc_pay_handle_buffer); payload_class->handle_event = GST_DEBUG_FUNCPTR( gst_rtp_sbc_pay_handle_event); /* properties */ g_object_class_install_property(G_OBJECT_CLASS(klass), PROP_MIN_FRAMES, g_param_spec_int("min-frames", "minimum frame number", "Minimum quantity of frames to send in one packet " "(-1 for maximum allowed by the mtu)", -1, G_MAXINT, DEFAULT_MIN_FRAMES, G_PARAM_READWRITE)); GST_DEBUG_CATEGORY_INIT(gst_rtp_sbc_pay_debug, "rtpsbcpay", 0, "RTP SBC payloader"); } static void gst_rtp_sbc_pay_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { GstRtpSBCPay *sbcpay; sbcpay = GST_RTP_SBC_PAY(object); switch (prop_id) { case PROP_MIN_FRAMES: sbcpay->min_frames = g_value_get_int(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_rtp_sbc_pay_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { GstRtpSBCPay *sbcpay; sbcpay = GST_RTP_SBC_PAY(object); switch (prop_id) { case PROP_MIN_FRAMES: g_value_set_int(value, sbcpay->min_frames); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; } } static void gst_rtp_sbc_pay_init(GstRtpSBCPay *self, GstRtpSBCPayClass *klass) { self->adapter = gst_adapter_new(); self->frame_length = 0; self->timestamp = 0; self->min_frames = DEFAULT_MIN_FRAMES; } gboolean gst_rtp_sbc_pay_plugin_init(GstPlugin *plugin) { return gst_element_register(plugin, "rtpsbcpay", GST_RANK_NONE, GST_TYPE_RTP_SBC_PAY); } bluez-4.101/audio/avdtp.h0000644000000000000000000002512411771117441012127 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ typedef enum { AVDTP_SESSION_STATE_DISCONNECTED, AVDTP_SESSION_STATE_CONNECTING, AVDTP_SESSION_STATE_CONNECTED } avdtp_session_state_t; struct avdtp; struct avdtp_stream; struct avdtp_local_sep; struct avdtp_remote_sep; struct avdtp_error { uint8_t category; union { uint8_t error_code; int posix_errno; } err; }; /* SEP capability categories */ #define AVDTP_MEDIA_TRANSPORT 0x01 #define AVDTP_REPORTING 0x02 #define AVDTP_RECOVERY 0x03 #define AVDTP_CONTENT_PROTECTION 0x04 #define AVDTP_HEADER_COMPRESSION 0x05 #define AVDTP_MULTIPLEXING 0x06 #define AVDTP_MEDIA_CODEC 0x07 #define AVDTP_DELAY_REPORTING 0x08 #define AVDTP_ERRNO 0xff /* AVDTP error definitions */ #define AVDTP_BAD_HEADER_FORMAT 0x01 #define AVDTP_BAD_LENGTH 0x11 #define AVDTP_BAD_ACP_SEID 0x12 #define AVDTP_SEP_IN_USE 0x13 #define AVDTP_SEP_NOT_IN_USE 0x14 #define AVDTP_BAD_SERV_CATEGORY 0x17 #define AVDTP_BAD_PAYLOAD_FORMAT 0x18 #define AVDTP_NOT_SUPPORTED_COMMAND 0x19 #define AVDTP_INVALID_CAPABILITIES 0x1A #define AVDTP_BAD_RECOVERY_TYPE 0x22 #define AVDTP_BAD_MEDIA_TRANSPORT_FORMAT 0x23 #define AVDTP_BAD_RECOVERY_FORMAT 0x25 #define AVDTP_BAD_ROHC_FORMAT 0x26 #define AVDTP_BAD_CP_FORMAT 0x27 #define AVDTP_BAD_MULTIPLEXING_FORMAT 0x28 #define AVDTP_UNSUPPORTED_CONFIGURATION 0x29 #define AVDTP_BAD_STATE 0x31 /* SEP types definitions */ #define AVDTP_SEP_TYPE_SOURCE 0x00 #define AVDTP_SEP_TYPE_SINK 0x01 /* Media types definitions */ #define AVDTP_MEDIA_TYPE_AUDIO 0x00 #define AVDTP_MEDIA_TYPE_VIDEO 0x01 #define AVDTP_MEDIA_TYPE_MULTIMEDIA 0x02 typedef enum { AVDTP_STATE_IDLE, AVDTP_STATE_CONFIGURED, AVDTP_STATE_OPEN, AVDTP_STATE_STREAMING, AVDTP_STATE_CLOSING, AVDTP_STATE_ABORTING, } avdtp_state_t; struct avdtp_service_capability { uint8_t category; uint8_t length; uint8_t data[0]; } __attribute__ ((packed)); #if __BYTE_ORDER == __LITTLE_ENDIAN struct avdtp_media_codec_capability { uint8_t rfa0:4; uint8_t media_type:4; uint8_t media_codec_type; uint8_t data[0]; } __attribute__ ((packed)); #elif __BYTE_ORDER == __BIG_ENDIAN struct avdtp_media_codec_capability { uint8_t media_type:4; uint8_t rfa0:4; uint8_t media_codec_type; uint8_t data[0]; } __attribute__ ((packed)); #else #error "Unknown byte order" #endif typedef void (*avdtp_session_state_cb) (struct audio_device *dev, struct avdtp *session, avdtp_session_state_t old_state, avdtp_session_state_t new_state, void *user_data); typedef void (*avdtp_stream_state_cb) (struct avdtp_stream *stream, avdtp_state_t old_state, avdtp_state_t new_state, struct avdtp_error *err, void *user_data); typedef void (*avdtp_set_configuration_cb) (struct avdtp *session, struct avdtp_stream *stream, struct avdtp_error *err); /* Callbacks for when a reply is received to a command that we sent */ struct avdtp_sep_cfm { void (*set_configuration) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); void (*get_configuration) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); void (*open) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); void (*start) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); void (*suspend) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); void (*close) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); void (*abort) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); void (*reconfigure) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); void (*delay_report) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data); }; /* Callbacks for indicating when we received a new command. The return value * indicates whether the command should be rejected or accepted */ struct avdtp_sep_ind { gboolean (*get_capability) (struct avdtp *session, struct avdtp_local_sep *sep, gboolean get_all, GSList **caps, uint8_t *err, void *user_data); gboolean (*set_configuration) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, GSList *caps, avdtp_set_configuration_cb cb, void *user_data); gboolean (*get_configuration) (struct avdtp *session, struct avdtp_local_sep *lsep, uint8_t *err, void *user_data); gboolean (*open) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, uint8_t *err, void *user_data); gboolean (*start) (struct avdtp *session, struct avdtp_local_sep *lsep, struct avdtp_stream *stream, uint8_t *err, void *user_data); gboolean (*suspend) (struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err, void *user_data); gboolean (*close) (struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err, void *user_data); void (*abort) (struct avdtp *session, struct avdtp_local_sep *sep, struct avdtp_stream *stream, uint8_t *err, void *user_data); gboolean (*reconfigure) (struct avdtp *session, struct avdtp_local_sep *lsep, uint8_t *err, void *user_data); gboolean (*delayreport) (struct avdtp *session, struct avdtp_local_sep *lsep, uint8_t rseid, uint16_t delay, uint8_t *err, void *user_data); }; typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps, struct avdtp_error *err, void *user_data); struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst); void avdtp_unref(struct avdtp *session); struct avdtp *avdtp_ref(struct avdtp *session); gboolean avdtp_is_connected(const bdaddr_t *src, const bdaddr_t *dst); struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category, void *data, int size); struct avdtp_remote_sep *avdtp_get_remote_sep(struct avdtp *session, uint8_t seid); uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep); uint8_t avdtp_get_type(struct avdtp_remote_sep *sep); struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep); gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep); struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep); int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb, void *user_data); gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream); unsigned int avdtp_stream_add_cb(struct avdtp *session, struct avdtp_stream *stream, avdtp_stream_state_cb cb, void *data); gboolean avdtp_stream_remove_cb(struct avdtp *session, struct avdtp_stream *stream, unsigned int id); gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock, uint16_t *imtu, uint16_t *omtu, GSList **caps); struct avdtp_service_capability *avdtp_stream_get_codec( struct avdtp_stream *stream); gboolean avdtp_stream_has_capability(struct avdtp_stream *stream, struct avdtp_service_capability *cap); gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream, GSList *caps); struct avdtp_remote_sep *avdtp_stream_get_remote_sep( struct avdtp_stream *stream); unsigned int avdtp_add_state_cb(avdtp_session_state_cb cb, void *user_data); gboolean avdtp_remove_state_cb(unsigned int id); int avdtp_set_configuration(struct avdtp *session, struct avdtp_remote_sep *rsep, struct avdtp_local_sep *lsep, GSList *caps, struct avdtp_stream **stream); int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream); int avdtp_open(struct avdtp *session, struct avdtp_stream *stream); int avdtp_reconfigure(struct avdtp *session, GSList *caps, struct avdtp_stream *stream); int avdtp_start(struct avdtp *session, struct avdtp_stream *stream); int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream); int avdtp_close(struct avdtp *session, struct avdtp_stream *stream, gboolean immediate); int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream); int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream, uint16_t delay); struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type, uint8_t media_type, uint8_t codec_type, gboolean delay_reporting, struct avdtp_sep_ind *ind, struct avdtp_sep_cfm *cfm, void *user_data); /* Find a matching pair of local and remote SEP ID's */ struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session, struct avdtp_local_sep *lsep); int avdtp_unregister_sep(struct avdtp_local_sep *sep); avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep); void avdtp_error_init(struct avdtp_error *err, uint8_t type, int id); const char *avdtp_strerror(struct avdtp_error *err); uint8_t avdtp_error_category(struct avdtp_error *err); int avdtp_error_error_code(struct avdtp_error *err); int avdtp_error_posix_errno(struct avdtp_error *err); void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst); void avdtp_set_auto_disconnect(struct avdtp *session, gboolean auto_dc); gboolean avdtp_stream_setup_active(struct avdtp *session); void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc); int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version); void avdtp_exit(const bdaddr_t *src); bluez-4.101/audio/telephony-maemo5.c0000644000000000000000000014651111766125764014213 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "log.h" #include "telephony.h" #include "error.h" /* SSC D-Bus definitions */ #define SSC_DBUS_NAME "com.nokia.phone.SSC" #define SSC_DBUS_IFACE "com.nokia.phone.SSC" #define SSC_DBUS_PATH "/com/nokia/phone/SSC" /* libcsnet D-Bus definitions */ #define NETWORK_BUS_NAME "com.nokia.phone.net" #define NETWORK_INTERFACE "Phone.Net" #define NETWORK_PATH "/com/nokia/phone/net" /* Mask bits for supported services */ #define NETWORK_MASK_GPRS_SUPPORT 0x01 #define NETWORK_MASK_CS_SERVICES 0x02 #define NETWORK_MASK_EGPRS_SUPPORT 0x04 #define NETWORK_MASK_HSDPA_AVAIL 0x08 #define NETWORK_MASK_HSUPA_AVAIL 0x10 /* network get cell info: cell type */ #define NETWORK_UNKNOWN_CELL 0 #define NETWORK_GSM_CELL 1 #define NETWORK_WCDMA_CELL 2 enum net_registration_status { NETWORK_REG_STATUS_HOME = 0x00, NETWORK_REG_STATUS_ROAM, NETWORK_REG_STATUS_ROAM_BLINK, NETWORK_REG_STATUS_NOSERV, NETWORK_REG_STATUS_NOSERV_SEARCHING, NETWORK_REG_STATUS_NOSERV_NOTSEARCHING, NETWORK_REG_STATUS_NOSERV_NOSIM, NETWORK_REG_STATUS_POWER_OFF = 0x08, NETWORK_REG_STATUS_NSPS, NETWORK_REG_STATUS_NSPS_NO_COVERAGE, NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW }; enum network_types { NETWORK_GSM_HOME_PLMN = 0, NETWORK_GSM_PREFERRED_PLMN, NETWORK_GSM_FORBIDDEN_PLMN, NETWORK_GSM_OTHER_PLMN, NETWORK_GSM_NO_PLMN_AVAIL }; enum network_alpha_tag_name_type { NETWORK_HARDCODED_LATIN_OPER_NAME = 0, NETWORK_HARDCODED_USC2_OPER_NAME, NETWORK_NITZ_SHORT_OPER_NAME, NETWORK_NITZ_FULL_OPER_NAME, }; #define TELEPHONY_MAEMO_PATH "/com/nokia/MaemoTelephony" #define TELEPHONY_MAEMO_INTERFACE "com.nokia.MaemoTelephony" #define CALLERID_BASE "/var/lib/bluetooth/maemo-callerid-" #define ALLOWED_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-allowed" #define RESTRICTED_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-restricted" #define NONE_FLAG_FILE "/var/lib/bluetooth/maemo-callerid-none" static uint32_t callerid = 0; /* CSD CALL plugin D-Bus definitions */ #define CSD_CALL_BUS_NAME "com.nokia.csd.Call" #define CSD_CALL_INTERFACE "com.nokia.csd.Call" #define CSD_CALL_INSTANCE "com.nokia.csd.Call.Instance" #define CSD_CALL_CONFERENCE "com.nokia.csd.Call.Conference" #define CSD_CALL_PATH "/com/nokia/csd/call" #define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference" /* Call status values as exported by the CSD CALL plugin */ #define CSD_CALL_STATUS_IDLE 0 #define CSD_CALL_STATUS_CREATE 1 #define CSD_CALL_STATUS_COMING 2 #define CSD_CALL_STATUS_PROCEEDING 3 #define CSD_CALL_STATUS_MO_ALERTING 4 #define CSD_CALL_STATUS_MT_ALERTING 5 #define CSD_CALL_STATUS_WAITING 6 #define CSD_CALL_STATUS_ANSWERED 7 #define CSD_CALL_STATUS_ACTIVE 8 #define CSD_CALL_STATUS_MO_RELEASE 9 #define CSD_CALL_STATUS_MT_RELEASE 10 #define CSD_CALL_STATUS_HOLD_INITIATED 11 #define CSD_CALL_STATUS_HOLD 12 #define CSD_CALL_STATUS_RETRIEVE_INITIATED 13 #define CSD_CALL_STATUS_RECONNECT_PENDING 14 #define CSD_CALL_STATUS_TERMINATED 15 #define CSD_CALL_STATUS_SWAP_INITIATED 16 #define CALL_FLAG_NONE 0 #define CALL_FLAG_PRESENTATION_ALLOWED 0x01 #define CALL_FLAG_PRESENTATION_RESTRICTED 0x02 /* SIM Phonebook D-Bus definitions */ #define SIM_PHONEBOOK_BUS_NAME "com.nokia.phone.SIM" #define SIM_PHONEBOOK_INTERFACE "Phone.Sim.Phonebook" #define SIM_PHONEBOOK_PATH "/com/nokia/phone/SIM/phonebook" #define PHONEBOOK_INDEX_FIRST_ENTRY 0xFFFF #define PHONEBOOK_INDEX_NEXT_FREE_LOCATION 0xFFFE enum sim_phonebook_type { SIM_PHONEBOOK_TYPE_ADN = 0x0, SIM_PHONEBOOK_TYPE_SDN, SIM_PHONEBOOK_TYPE_FDN, SIM_PHONEBOOK_TYPE_VMBX, SIM_PHONEBOOK_TYPE_MBDN, SIM_PHONEBOOK_TYPE_EN, SIM_PHONEBOOK_TYPE_MSISDN }; enum sim_phonebook_location_type { SIM_PHONEBOOK_LOCATION_EXACT = 0x0, SIM_PHONEBOOK_LOCATION_NEXT }; struct csd_call { char *object_path; int status; gboolean originating; gboolean emergency; gboolean on_hold; gboolean conference; char *number; gboolean setup; }; static struct { uint8_t status; uint16_t lac; uint32_t cell_id; uint32_t operator_code; uint32_t country_code; uint8_t network_type; uint8_t supported_services; uint16_t signals_bar; char *operator_name; } net = { .status = NETWORK_REG_STATUS_NOSERV, .lac = 0, .cell_id = 0, .operator_code = 0, .country_code = 0, .network_type = NETWORK_GSM_NO_PLMN_AVAIL, .supported_services = 0, .signals_bar = 0, .operator_name = NULL, }; static DBusConnection *connection = NULL; static GSList *calls = NULL; /* Reference count for determining the call indicator status */ static GSList *active_calls = NULL; static char *msisdn = NULL; /* Subscriber number */ static char *vmbx = NULL; /* Voice mailbox number */ /* HAL battery namespace key values */ static int battchg_cur = -1; /* "battery.charge_level.current" */ static int battchg_last = -1; /* "battery.charge_level.last_full" */ static int battchg_design = -1; /* "battery.charge_level.design" */ static gboolean get_calls_active = FALSE; static gboolean events_enabled = FALSE; /* Supported set of call hold operations */ static const char *chld_str = "0,1,1x,2,2x,3,4"; static char *last_dialed_number = NULL; /* Timer for tracking call creation requests */ static guint create_request_timer = 0; static struct indicator maemo_indicators[] = { { "battchg", "0-5", 5, TRUE }, { "signal", "0-5", 0, TRUE }, { "service", "0,1", 0, TRUE }, { "call", "0,1", 0, TRUE }, { "callsetup", "0-3", 0, TRUE }, { "callheld", "0-2", 0, FALSE }, { "roam", "0,1", 0, TRUE }, { NULL } }; static char *call_status_str[] = { "IDLE", "CREATE", "COMING", "PROCEEDING", "MO_ALERTING", "MT_ALERTING", "WAITING", "ANSWERED", "ACTIVE", "MO_RELEASE", "MT_RELEASE", "HOLD_INITIATED", "HOLD", "RETRIEVE_INITIATED", "RECONNECT_PENDING", "TERMINATED", "SWAP_INITIATED", "???" }; static struct csd_call *find_call(const char *path) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (g_str_equal(call->object_path, path)) return call; } return NULL; } static struct csd_call *find_non_held_call(void) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (call->status == CSD_CALL_STATUS_IDLE) continue; if (call->status != CSD_CALL_STATUS_HOLD) return call; } return NULL; } static struct csd_call *find_non_idle_call(void) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (call->status != CSD_CALL_STATUS_IDLE) return call; } return NULL; } static struct csd_call *find_call_with_status(int status) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (call->status == status) return call; } return NULL; } static int release_conference(void) { DBusMessage *msg; DBG("telephony-maemo: releasing conference call"); msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_CONFERENCE_PATH, CSD_CALL_INSTANCE, "Release"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int release_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, call->object_path, CSD_CALL_INSTANCE, "Release"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int answer_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, call->object_path, CSD_CALL_INSTANCE, "Answer"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int split_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, call->object_path, CSD_CALL_INSTANCE, "Split"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int unhold_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Unhold"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int hold_call(struct csd_call *call) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Hold"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int swap_calls(void) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Swap"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int create_conference(void) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Conference"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int call_transfer(void) { DBusMessage *msg; msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "Transfer"); if (!msg) { error("Unable to allocate new D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, msg); return 0; } static int number_type(const char *number) { if (number == NULL) return NUMBER_TYPE_TELEPHONY; if (number[0] == '+' || strncmp(number, "00", 2) == 0) return NUMBER_TYPE_INTERNATIONAL; return NUMBER_TYPE_TELEPHONY; } void telephony_device_connected(void *telephony_device) { struct csd_call *coming; DBG("telephony-maemo: device %p connected", telephony_device); coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING); if (coming) { if (find_call_with_status(CSD_CALL_STATUS_ACTIVE)) telephony_call_waiting_ind(coming->number, number_type(coming->number)); else telephony_incoming_call_ind(coming->number, number_type(coming->number)); } } void telephony_device_disconnected(void *telephony_device) { DBG("telephony-maemo: device %p disconnected", telephony_device); events_enabled = FALSE; } void telephony_event_reporting_req(void *telephony_device, int ind) { events_enabled = ind == 1 ? TRUE : FALSE; telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE); } void telephony_response_and_hold_req(void *telephony_device, int rh) { telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED); } void telephony_last_dialed_number_req(void *telephony_device) { DBG("telephony-maemo: last dialed number request"); if (last_dialed_number) telephony_dial_number_req(telephony_device, last_dialed_number); else telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NOT_ALLOWED); } void telephony_terminate_call_req(void *telephony_device) { struct csd_call *call; int err; call = find_call_with_status(CSD_CALL_STATUS_ACTIVE); if (!call) call = find_non_idle_call(); if (!call) { error("No active call"); telephony_terminate_call_rsp(telephony_device, CME_ERROR_NOT_ALLOWED); return; } if (call->conference) err = release_conference(); else err = release_call(call); if (err < 0) telephony_terminate_call_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE); } void telephony_answer_call_req(void *telephony_device) { struct csd_call *call; call = find_call_with_status(CSD_CALL_STATUS_COMING); if (!call) call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING); if (!call) call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING); if (!call) call = find_call_with_status(CSD_CALL_STATUS_WAITING); if (!call) { telephony_answer_call_rsp(telephony_device, CME_ERROR_NOT_ALLOWED); return; } if (answer_call(call) < 0) telephony_answer_call_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE); } static int send_method_call(const char *dest, const char *path, const char *interface, const char *method, DBusPendingCallNotifyFunction cb, void *user_data, int type, ...) { DBusMessage *msg; DBusPendingCall *call; va_list args; msg = dbus_message_new_method_call(dest, path, interface, method); if (!msg) { error("Unable to allocate new D-Bus %s message", method); return -ENOMEM; } va_start(args, type); if (!dbus_message_append_args_valist(msg, type, args)) { dbus_message_unref(msg); va_end(args); return -EIO; } va_end(args); if (!cb) { g_dbus_send_message(connection, msg); return 0; } if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) { error("Sending %s failed", method); dbus_message_unref(msg); return -EIO; } dbus_pending_call_set_notify(call, cb, user_data, NULL); dbus_pending_call_unref(call); dbus_message_unref(msg); return 0; } static const char *memory_dial_lookup(int location) { if (location == 1) return vmbx; else return NULL; } void telephony_dial_number_req(void *telephony_device, const char *number) { uint32_t flags = callerid; int ret; DBG("telephony-maemo: dial request to %s", number); if (strncmp(number, "*31#", 4) == 0) { number += 4; flags = CALL_FLAG_PRESENTATION_ALLOWED; } else if (strncmp(number, "#31#", 4) == 0) { number += 4; flags = CALL_FLAG_PRESENTATION_RESTRICTED; } else if (number[0] == '>') { const char *location = &number[1]; number = memory_dial_lookup(strtol(&number[1], NULL, 0)); if (!number) { error("No number at memory location %s", location); telephony_dial_number_rsp(telephony_device, CME_ERROR_INVALID_INDEX); return; } } ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "CreateWith", NULL, NULL, DBUS_TYPE_STRING, &number, DBUS_TYPE_UINT32, &flags, DBUS_TYPE_INVALID); if (ret < 0) { telephony_dial_number_rsp(telephony_device, CME_ERROR_AG_FAILURE); return; } telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE); } void telephony_transmit_dtmf_req(void *telephony_device, char tone) { int ret; char buf[2] = { tone, '\0' }, *buf_ptr = buf; DBG("telephony-maemo: transmit dtmf: %s", buf); ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "SendDTMF", NULL, NULL, DBUS_TYPE_STRING, &buf_ptr, DBUS_TYPE_INVALID); if (ret < 0) { telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_AG_FAILURE); return; } telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE); } void telephony_subscriber_number_req(void *telephony_device) { DBG("telephony-maemo: subscriber number request"); if (msisdn) telephony_subscriber_number_ind(msisdn, number_type(msisdn), SUBSCRIBER_SERVICE_VOICE); telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE); } static int csd_status_to_hfp(struct csd_call *call) { switch (call->status) { case CSD_CALL_STATUS_IDLE: case CSD_CALL_STATUS_MO_RELEASE: case CSD_CALL_STATUS_MT_RELEASE: case CSD_CALL_STATUS_TERMINATED: return -1; case CSD_CALL_STATUS_CREATE: return CALL_STATUS_DIALING; case CSD_CALL_STATUS_WAITING: return CALL_STATUS_WAITING; case CSD_CALL_STATUS_PROCEEDING: /* PROCEEDING can happen in outgoing/incoming */ if (call->originating) return CALL_STATUS_DIALING; else return CALL_STATUS_INCOMING; case CSD_CALL_STATUS_COMING: return CALL_STATUS_INCOMING; case CSD_CALL_STATUS_MO_ALERTING: return CALL_STATUS_ALERTING; case CSD_CALL_STATUS_MT_ALERTING: return CALL_STATUS_INCOMING; case CSD_CALL_STATUS_ANSWERED: case CSD_CALL_STATUS_ACTIVE: case CSD_CALL_STATUS_RECONNECT_PENDING: case CSD_CALL_STATUS_SWAP_INITIATED: case CSD_CALL_STATUS_HOLD_INITIATED: return CALL_STATUS_ACTIVE; case CSD_CALL_STATUS_RETRIEVE_INITIATED: case CSD_CALL_STATUS_HOLD: return CALL_STATUS_HELD; default: return -1; } } void telephony_list_current_calls_req(void *telephony_device) { GSList *l; int i; DBG("telephony-maemo: list current calls request"); for (l = calls, i = 1; l != NULL; l = l->next, i++) { struct csd_call *call = l->data; int status, direction, multiparty; status = csd_status_to_hfp(call); if (status < 0) continue; direction = call->originating ? CALL_DIR_OUTGOING : CALL_DIR_INCOMING; multiparty = call->conference ? CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO; telephony_list_current_call_ind(i, direction, status, CALL_MODE_VOICE, multiparty, call->number, number_type(call->number)); } telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE); } void telephony_operator_selection_req(void *telephony_device) { telephony_operator_selection_ind(OPERATOR_MODE_AUTO, net.operator_name ? net.operator_name : ""); telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE); } static void foreach_call_with_status(int status, int (*func)(struct csd_call *call)) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct csd_call *call = l->data; if (call->status == status) func(call); } } void telephony_call_hold_req(void *telephony_device, const char *cmd) { const char *idx; struct csd_call *call; int err = 0; DBG("telephony-maemo: got call hold request %s", cmd); if (strlen(cmd) > 1) idx = &cmd[1]; else idx = NULL; if (idx) call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1); else call = NULL; switch (cmd[0]) { case '0': foreach_call_with_status(CSD_CALL_STATUS_HOLD, release_call); foreach_call_with_status(CSD_CALL_STATUS_WAITING, release_call); break; case '1': if (idx) { if (call) err = release_call(call); break; } foreach_call_with_status(CSD_CALL_STATUS_ACTIVE, release_call); call = find_call_with_status(CSD_CALL_STATUS_WAITING); if (call) err = answer_call(call); break; case '2': if (idx) { if (call) err = split_call(call); } else { struct csd_call *held, *wait; call = find_call_with_status(CSD_CALL_STATUS_ACTIVE); held = find_call_with_status(CSD_CALL_STATUS_HOLD); wait = find_call_with_status(CSD_CALL_STATUS_WAITING); if (wait) err = answer_call(wait); else if (call && held) err = swap_calls(); else { if (call) err = hold_call(call); if (held) err = unhold_call(held); } } break; case '3': if (find_call_with_status(CSD_CALL_STATUS_HOLD) || find_call_with_status(CSD_CALL_STATUS_WAITING)) err = create_conference(); break; case '4': err = call_transfer(); break; default: DBG("Unknown call hold request"); break; } if (err) telephony_call_hold_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE); } void telephony_nr_and_ec_req(void *telephony_device, gboolean enable) { DBG("telephony-maemo: got %s NR and EC request", enable ? "enable" : "disable"); telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE); } void telephony_key_press_req(void *telephony_device, const char *keys) { struct csd_call *active, *waiting; int err; DBG("telephony-maemo: got key press request for %s", keys); waiting = find_call_with_status(CSD_CALL_STATUS_COMING); if (!waiting) waiting = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING); if (!waiting) waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING); active = find_call_with_status(CSD_CALL_STATUS_ACTIVE); if (waiting) err = answer_call(waiting); else if (active) err = release_call(active); else err = 0; if (err < 0) telephony_key_press_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_key_press_rsp(telephony_device, CME_ERROR_NONE); } void telephony_voice_dial_req(void *telephony_device, gboolean enable) { DBG("telephony-maemo: got %s voice dial request", enable ? "enable" : "disable"); telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED); } static void handle_incoming_call(DBusMessage *msg) { const char *number, *call_path; struct csd_call *call; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &call_path, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) { error("Unexpected parameters in Call.Coming() signal"); return; } call = find_call(call_path); if (!call) { error("Didn't find any matching call object for %s", call_path); return; } DBG("Incoming call to %s from number %s", call_path, number); g_free(call->number); call->number = g_strdup(number); telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_INCOMING); if (find_call_with_status(CSD_CALL_STATUS_ACTIVE)) telephony_call_waiting_ind(call->number, number_type(call->number)); else telephony_incoming_call_ind(call->number, number_type(call->number)); } static void handle_outgoing_call(DBusMessage *msg) { const char *number, *call_path; struct csd_call *call; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &call_path, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) { error("Unexpected parameters in Call.Created() signal"); return; } call = find_call(call_path); if (!call) { error("Didn't find any matching call object for %s", call_path); return; } DBG("Outgoing call from %s to number %s", call_path, number); g_free(call->number); call->number = g_strdup(number); g_free(last_dialed_number); last_dialed_number = g_strdup(number); if (create_request_timer) { g_source_remove(create_request_timer); create_request_timer = 0; } } static gboolean create_timeout(gpointer user_data) { telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_INACTIVE); create_request_timer = 0; return FALSE; } static void handle_create_requested(DBusMessage *msg) { DBG("Call.CreateRequested()"); if (create_request_timer) g_source_remove(create_request_timer); create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL); telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_OUTGOING); } static void handle_call_status(DBusMessage *msg, const char *call_path) { struct csd_call *call; dbus_uint32_t status, cause_type, cause; int callheld = telephony_get_indicator(maemo_indicators, "callheld"); if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &status, DBUS_TYPE_UINT32, &cause_type, DBUS_TYPE_UINT32, &cause, DBUS_TYPE_INVALID)) { error("Unexpected parameters in Instance.CallStatus() signal"); return; } call = find_call(call_path); if (!call) { error("Didn't find any matching call object for %s", call_path); return; } if (status > 16) { error("Invalid call status %u", status); return; } DBG("Call %s changed from %s to %s", call_path, call_status_str[call->status], call_status_str[status]); if (call->status == (int) status) { DBG("Ignoring CSD Call state change to existing state"); return; } call->status = (int) status; switch (status) { case CSD_CALL_STATUS_IDLE: if (call->setup) { telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_INACTIVE); if (!call->originating) telephony_calling_stopped_ind(); } g_free(call->number); call->number = NULL; call->originating = FALSE; call->emergency = FALSE; call->on_hold = FALSE; call->conference = FALSE; call->setup = FALSE; break; case CSD_CALL_STATUS_CREATE: call->originating = TRUE; call->setup = TRUE; break; case CSD_CALL_STATUS_COMING: call->originating = FALSE; call->setup = TRUE; break; case CSD_CALL_STATUS_PROCEEDING: break; case CSD_CALL_STATUS_MO_ALERTING: telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_ALERTING); break; case CSD_CALL_STATUS_MT_ALERTING: break; case CSD_CALL_STATUS_WAITING: break; case CSD_CALL_STATUS_ANSWERED: break; case CSD_CALL_STATUS_ACTIVE: if (call->on_hold) { call->on_hold = FALSE; if (find_call_with_status(CSD_CALL_STATUS_HOLD)) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_MULTIPLE); else telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_NONE); } else { if (!g_slist_find(active_calls, call)) active_calls = g_slist_prepend(active_calls, call); if (g_slist_length(active_calls) == 1) telephony_update_indicator(maemo_indicators, "call", EV_CALL_ACTIVE); /* Upgrade callheld status if necessary */ if (callheld == EV_CALLHELD_ON_HOLD) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_MULTIPLE); telephony_update_indicator(maemo_indicators, "callsetup", EV_CALLSETUP_INACTIVE); if (!call->originating) telephony_calling_stopped_ind(); call->setup = FALSE; } break; case CSD_CALL_STATUS_MO_RELEASE: case CSD_CALL_STATUS_MT_RELEASE: active_calls = g_slist_remove(active_calls, call); if (g_slist_length(active_calls) == 0) telephony_update_indicator(maemo_indicators, "call", EV_CALL_INACTIVE); break; case CSD_CALL_STATUS_HOLD_INITIATED: break; case CSD_CALL_STATUS_HOLD: call->on_hold = TRUE; if (find_non_held_call()) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_MULTIPLE); else telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_ON_HOLD); break; case CSD_CALL_STATUS_RETRIEVE_INITIATED: break; case CSD_CALL_STATUS_RECONNECT_PENDING: break; case CSD_CALL_STATUS_TERMINATED: if (call->on_hold && !find_call_with_status(CSD_CALL_STATUS_HOLD)) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_NONE); else if (callheld == EV_CALLHELD_MULTIPLE && find_call_with_status(CSD_CALL_STATUS_HOLD)) telephony_update_indicator(maemo_indicators, "callheld", EV_CALLHELD_ON_HOLD); break; case CSD_CALL_STATUS_SWAP_INITIATED: break; default: error("Unknown call status %u", status); break; } } static void handle_conference(DBusMessage *msg, gboolean joined) { const char *path; struct csd_call *call; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { error("Unexpected parameters in Conference.%s", dbus_message_get_member(msg)); return; } call = find_call(path); if (!call) { error("Conference signal for unknown call %s", path); return; } DBG("Call %s %s the conference", path, joined ? "joined" : "left"); call->conference = joined; } static void get_operator_name_reply(DBusPendingCall *pending_call, void *user_data) { DBusMessage *reply; DBusError err; const char *name; dbus_int32_t net_err; reply = dbus_pending_call_steal_reply(pending_call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("get_operator_name failed: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_error_init(&err); if (!dbus_message_get_args(reply, &err, DBUS_TYPE_STRING, &name, DBUS_TYPE_INT32, &net_err, DBUS_TYPE_INVALID)) { error("Unexpected get_operator_name reply parameters: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } if (net_err != 0) { error("get_operator_name failed with code %d", net_err); goto done; } if (strlen(name) == 0) goto done; g_free(net.operator_name); net.operator_name = g_strdup(name); DBG("telephony-maemo: operator name updated: %s", name); done: dbus_message_unref(reply); } static void resolve_operator_name(uint32_t operator, uint32_t country) { uint8_t name_type = NETWORK_HARDCODED_LATIN_OPER_NAME; send_method_call(NETWORK_BUS_NAME, NETWORK_PATH, NETWORK_INTERFACE, "get_operator_name", get_operator_name_reply, NULL, DBUS_TYPE_BYTE, &name_type, DBUS_TYPE_UINT32, &operator, DBUS_TYPE_UINT32, &country, DBUS_TYPE_INVALID); } static void update_registration_status(uint8_t status, uint16_t lac, uint32_t cell_id, uint32_t operator_code, uint32_t country_code, uint8_t network_type, uint8_t supported_services) { if (net.status != status) { switch (status) { case NETWORK_REG_STATUS_HOME: telephony_update_indicator(maemo_indicators, "roam", EV_ROAM_INACTIVE); if (net.status >= NETWORK_REG_STATUS_NOSERV) telephony_update_indicator(maemo_indicators, "service", EV_SERVICE_PRESENT); break; case NETWORK_REG_STATUS_ROAM: case NETWORK_REG_STATUS_ROAM_BLINK: telephony_update_indicator(maemo_indicators, "roam", EV_ROAM_ACTIVE); if (net.status >= NETWORK_REG_STATUS_NOSERV) telephony_update_indicator(maemo_indicators, "service", EV_SERVICE_PRESENT); break; case NETWORK_REG_STATUS_NOSERV: case NETWORK_REG_STATUS_NOSERV_SEARCHING: case NETWORK_REG_STATUS_NOSERV_NOTSEARCHING: case NETWORK_REG_STATUS_NOSERV_NOSIM: case NETWORK_REG_STATUS_POWER_OFF: case NETWORK_REG_STATUS_NSPS: case NETWORK_REG_STATUS_NSPS_NO_COVERAGE: case NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW: if (net.status < NETWORK_REG_STATUS_NOSERV) telephony_update_indicator(maemo_indicators, "service", EV_SERVICE_NONE); break; } net.status = status; } net.lac = lac; net.cell_id = cell_id; if (net.operator_code != operator_code || net.country_code != country_code) { g_free(net.operator_name); net.operator_name = NULL; resolve_operator_name(operator_code, country_code); net.operator_code = operator_code; net.country_code = country_code; } net.network_type = network_type; net.supported_services = supported_services; } static void handle_registration_status_change(DBusMessage *msg) { uint8_t status; dbus_uint16_t lac, network_type, supported_services; dbus_uint32_t cell_id, operator_code, country_code; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BYTE, &status, DBUS_TYPE_UINT16, &lac, DBUS_TYPE_UINT32, &cell_id, DBUS_TYPE_UINT32, &operator_code, DBUS_TYPE_UINT32, &country_code, DBUS_TYPE_BYTE, &network_type, DBUS_TYPE_BYTE, &supported_services, DBUS_TYPE_INVALID)) { error("Unexpected parameters in registration_status_change"); return; } update_registration_status(status, lac, cell_id, operator_code, country_code, network_type, supported_services); } static void update_signal_strength(uint8_t signals_bar) { int signal; if (signals_bar > 100) { DBG("signals_bar greater than expected: %u", signals_bar); signals_bar = 100; } if (net.signals_bar == signals_bar) return; /* A simple conversion from 0-100 to 0-5 (used by HFP) */ signal = (signals_bar + 20) / 21; telephony_update_indicator(maemo_indicators, "signal", signal); net.signals_bar = signals_bar; DBG("Signal strength updated: %u/100, %d/5", signals_bar, signal); } static void handle_signal_strength_change(DBusMessage *msg) { uint8_t signals_bar, rssi_in_dbm; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BYTE, &signals_bar, DBUS_TYPE_BYTE, &rssi_in_dbm, DBUS_TYPE_INVALID)) { error("Unexpected parameters in signal_strength_change"); return; } update_signal_strength(signals_bar); } static gboolean iter_get_basic_args(DBusMessageIter *iter, int first_arg_type, ...) { int type; va_list ap; va_start(ap, first_arg_type); for (type = first_arg_type; type != DBUS_TYPE_INVALID; type = va_arg(ap, int)) { void *value = va_arg(ap, void *); int real_type = dbus_message_iter_get_arg_type(iter); if (real_type != type) { error("iter_get_basic_args: expected %c but got %c", (char) type, (char) real_type); break; } dbus_message_iter_get_basic(iter, value); dbus_message_iter_next(iter); } va_end(ap); return type == DBUS_TYPE_INVALID ? TRUE : FALSE; } static void hal_battery_level_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; dbus_int32_t level; int *value = user_data; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("hald replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_error_init(&err); if (dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &level, DBUS_TYPE_INVALID) == FALSE) { error("Unable to parse GetPropertyInteger reply: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } *value = (int) level; if (value == &battchg_last) DBG("telephony-maemo: battery.charge_level.last_full is %d", *value); else if (value == &battchg_design) DBG("telephony-maemo: battery.charge_level.design is %d", *value); else DBG("telephony-maemo: battery.charge_level.current is %d", *value); if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) { int new, max; if (battchg_last > 0) max = battchg_last; else max = battchg_design; new = battchg_cur * 5 / max; telephony_update_indicator(maemo_indicators, "battchg", new); } done: dbus_message_unref(reply); } static void hal_get_integer(const char *path, const char *key, void *user_data) { send_method_call("org.freedesktop.Hal", path, "org.freedesktop.Hal.Device", "GetPropertyInteger", hal_battery_level_reply, user_data, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID); } static void handle_hal_property_modified(DBusMessage *msg) { DBusMessageIter iter, array; dbus_int32_t num_changes; const char *path; path = dbus_message_get_path(msg); dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) { error("Unexpected signature in hal PropertyModified signal"); return; } dbus_message_iter_get_basic(&iter, &num_changes); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature in hal PropertyModified signal"); return; } dbus_message_iter_recurse(&iter, &array); while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) { DBusMessageIter prop; const char *name; dbus_bool_t added, removed; dbus_message_iter_recurse(&array, &prop); if (!iter_get_basic_args(&prop, DBUS_TYPE_STRING, &name, DBUS_TYPE_BOOLEAN, &added, DBUS_TYPE_BOOLEAN, &removed, DBUS_TYPE_INVALID)) { error("Invalid hal PropertyModified parameters"); break; } if (g_str_equal(name, "battery.charge_level.last_full")) hal_get_integer(path, name, &battchg_last); else if (g_str_equal(name, "battery.charge_level.current")) hal_get_integer(path, name, &battchg_cur); else if (g_str_equal(name, "battery.charge_level.design")) hal_get_integer(path, name, &battchg_design); dbus_message_iter_next(&array); } } static void csd_call_free(struct csd_call *call) { if (!call) return; g_free(call->object_path); g_free(call->number); g_free(call); } static void parse_call_list(DBusMessageIter *iter) { do { DBusMessageIter call_iter; struct csd_call *call; const char *object_path, *number; dbus_uint32_t status; dbus_bool_t originating, terminating, emerg, on_hold, conf; if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) { error("Unexpected signature in GetCallInfoAll reply"); break; } dbus_message_iter_recurse(iter, &call_iter); if (!iter_get_basic_args(&call_iter, DBUS_TYPE_OBJECT_PATH, &object_path, DBUS_TYPE_UINT32, &status, DBUS_TYPE_BOOLEAN, &originating, DBUS_TYPE_BOOLEAN, &terminating, DBUS_TYPE_BOOLEAN, &emerg, DBUS_TYPE_BOOLEAN, &on_hold, DBUS_TYPE_BOOLEAN, &conf, DBUS_TYPE_STRING, &number, DBUS_TYPE_INVALID)) { error("Parsing call D-Bus parameters failed"); break; } call = find_call(object_path); if (!call) { call = g_new0(struct csd_call, 1); call->object_path = g_strdup(object_path); call->status = (int) status; calls = g_slist_append(calls, call); DBG("telephony-maemo: new csd call instance at %s", object_path); } if (call->status == CSD_CALL_STATUS_IDLE) continue; /* CSD gives incorrect call_hold property sometimes */ if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) || (call->status == CSD_CALL_STATUS_HOLD && !on_hold)) { error("Conflicting call status and on_hold property!"); on_hold = call->status == CSD_CALL_STATUS_HOLD; } call->originating = originating; call->on_hold = on_hold; call->conference = conf; g_free(call->number); call->number = g_strdup(number); } while (dbus_message_iter_next(iter)); } static void signal_strength_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; uint8_t signals_bar, rssi_in_dbm; dbus_int32_t net_err; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("Unable to get signal strength: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_error_init(&err); if (!dbus_message_get_args(reply, &err, DBUS_TYPE_BYTE, &signals_bar, DBUS_TYPE_BYTE, &rssi_in_dbm, DBUS_TYPE_INT32, &net_err, DBUS_TYPE_INVALID)) { error("Unable to parse signal_strength reply: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } if (net_err != 0) { error("get_signal_strength failed with code %d", net_err); goto done; } update_signal_strength(signals_bar); done: dbus_message_unref(reply); } static int get_signal_strength(void) { return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH, NETWORK_INTERFACE, "get_signal_strength", signal_strength_reply, NULL, DBUS_TYPE_INVALID); } static void registration_status_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; uint8_t status; dbus_uint16_t lac, network_type, supported_services; dbus_uint32_t cell_id, operator_code, country_code; dbus_int32_t net_err; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("Unable to get registration status: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_error_init(&err); if (!dbus_message_get_args(reply, &err, DBUS_TYPE_BYTE, &status, DBUS_TYPE_UINT16, &lac, DBUS_TYPE_UINT32, &cell_id, DBUS_TYPE_UINT32, &operator_code, DBUS_TYPE_UINT32, &country_code, DBUS_TYPE_BYTE, &network_type, DBUS_TYPE_BYTE, &supported_services, DBUS_TYPE_INT32, &net_err, DBUS_TYPE_INVALID)) { error("Unable to parse registration_status_change reply:" " %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } if (net_err != 0) { error("get_registration_status failed with code %d", net_err); goto done; } update_registration_status(status, lac, cell_id, operator_code, country_code, network_type, supported_services); get_signal_strength(); done: dbus_message_unref(reply); } static int get_registration_status(void) { return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH, NETWORK_INTERFACE, "get_registration_status", registration_status_reply, NULL, DBUS_TYPE_INVALID); } static void call_info_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; DBusMessageIter iter, sub; get_calls_active = FALSE; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("csd replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature in GetCallInfoAll return"); goto done; } dbus_message_iter_recurse(&iter, &sub); parse_call_list(&sub); get_registration_status(); done: dbus_message_unref(reply); } static void hal_find_device_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; DBusMessageIter iter, sub; const char *path; char match_string[256]; int type; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("hald replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature in FindDeviceByCapability return"); goto done; } dbus_message_iter_recurse(&iter, &sub); type = dbus_message_iter_get_arg_type(&sub); if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) { error("No hal device with battery capability found"); goto done; } dbus_message_iter_get_basic(&sub, &path); DBG("telephony-maemo: found battery device at %s", path); snprintf(match_string, sizeof(match_string), "type='signal'," "path='%s'," "interface='org.freedesktop.Hal.Device'," "member='PropertyModified'", path); dbus_bus_add_match(connection, match_string, NULL); hal_get_integer(path, "battery.charge_level.last_full", &battchg_last); hal_get_integer(path, "battery.charge_level.current", &battchg_cur); hal_get_integer(path, "battery.charge_level.design", &battchg_design); done: dbus_message_unref(reply); } static void phonebook_read_reply(DBusPendingCall *call, void *user_data) { DBusError derr; DBusMessage *reply; const char *name, *number; char **number_type = user_data; dbus_int32_t current_location, err; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&derr); if (dbus_set_error_from_message(&derr, reply)) { error("SIM.Phonebook replied with an error: %s, %s", derr.name, derr.message); dbus_error_free(&derr); goto done; } dbus_error_init(&derr); if (dbus_message_get_args(reply, &derr, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &number, DBUS_TYPE_INT32, ¤t_location, DBUS_TYPE_INT32, &err, DBUS_TYPE_INVALID) == FALSE) { error("Unable to parse SIM.Phonebook.read arguments: %s, %s", derr.name, derr.message); dbus_error_free(&derr); goto done; } if (err != 0) { error("SIM.Phonebook.read failed with error %d", err); if (number_type == &vmbx) vmbx = g_strdup(getenv("VMBX_NUMBER")); goto done; } if (number_type == &msisdn) { g_free(msisdn); msisdn = g_strdup(number); DBG("Got MSISDN %s (%s)", number, name); } else { g_free(vmbx); vmbx = g_strdup(number); DBG("Got voice mailbox number %s (%s)", number, name); } done: dbus_message_unref(reply); } static void csd_init(void) { dbus_uint32_t location; uint8_t pb_type, location_type; int ret; ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH, CSD_CALL_INTERFACE, "GetCallInfoAll", call_info_reply, NULL, DBUS_TYPE_INVALID); if (ret < 0) { error("Unable to sent GetCallInfoAll method call"); return; } get_calls_active = TRUE; pb_type = SIM_PHONEBOOK_TYPE_MSISDN; location = PHONEBOOK_INDEX_FIRST_ENTRY; location_type = SIM_PHONEBOOK_LOCATION_NEXT; ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH, SIM_PHONEBOOK_INTERFACE, "read", phonebook_read_reply, &msisdn, DBUS_TYPE_BYTE, &pb_type, DBUS_TYPE_INT32, &location, DBUS_TYPE_BYTE, &location_type, DBUS_TYPE_INVALID); if (ret < 0) { error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()"); return; } pb_type = SIM_PHONEBOOK_TYPE_MBDN; location = PHONEBOOK_INDEX_FIRST_ENTRY; location_type = SIM_PHONEBOOK_LOCATION_NEXT; ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH, SIM_PHONEBOOK_INTERFACE, "read", phonebook_read_reply, &vmbx, DBUS_TYPE_BYTE, &pb_type, DBUS_TYPE_INT32, &location, DBUS_TYPE_BYTE, &location_type, DBUS_TYPE_INVALID); if (ret < 0) { error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()"); return; } } static uint32_t get_callflag(const char *callerid_setting) { if (callerid_setting != NULL) { if (g_str_equal(callerid_setting, "allowed")) return CALL_FLAG_PRESENTATION_ALLOWED; else if (g_str_equal(callerid_setting, "restricted")) return CALL_FLAG_PRESENTATION_RESTRICTED; else return CALL_FLAG_NONE; } else return CALL_FLAG_NONE; } static void generate_flag_file(const char *filename) { int fd; if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS) || g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS) || g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS)) return; fd = open(filename, O_WRONLY | O_CREAT, 0); if (fd >= 0) close(fd); } static void save_callerid_to_file(const char *callerid_setting) { char callerid_file[FILENAME_MAX]; snprintf(callerid_file, sizeof(callerid_file), "%s%s", CALLERID_BASE, callerid_setting); if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS)) rename(ALLOWED_FLAG_FILE, callerid_file); else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS)) rename(RESTRICTED_FLAG_FILE, callerid_file); else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS)) rename(NONE_FLAG_FILE, callerid_file); else generate_flag_file(callerid_file); } static uint32_t callerid_from_file(void) { if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS)) return CALL_FLAG_PRESENTATION_ALLOWED; else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS)) return CALL_FLAG_PRESENTATION_RESTRICTED; else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS)) return CALL_FLAG_NONE; else return CALL_FLAG_NONE; } static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg, void *data) { const char *callerid_setting; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &callerid_setting, DBUS_TYPE_INVALID) == FALSE) return btd_error_invalid_args(msg); if (g_str_equal(callerid_setting, "allowed") || g_str_equal(callerid_setting, "restricted") || g_str_equal(callerid_setting, "none")) { save_callerid_to_file(callerid_setting); callerid = get_callflag(callerid_setting); DBG("telephony-maemo setting callerid flag: %s", callerid_setting); return dbus_message_new_method_return(msg); } error("telephony-maemo: invalid argument %s for method call" " SetCallerId", callerid_setting); return btd_error_invalid_args(msg); } static const GDBusMethodTable telephony_maemo_methods[] = { { GDBUS_ASYNC_METHOD("SetCallerId", GDBUS_ARGS({ "id", "s" }), NULL, set_callerid) }, { } }; static void handle_modem_state(DBusMessage *msg) { const char *state; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state, DBUS_TYPE_INVALID)) { error("Unexpected modem state parameters"); return; } DBG("SSC modem state: %s", state); if (calls != NULL || get_calls_active) return; if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online")) csd_init(); } static void modem_state_reply(DBusPendingCall *call, void *user_data) { DBusMessage *reply = dbus_pending_call_steal_reply(call); DBusError err; dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("get_modem_status: %s, %s", err.name, err.message); dbus_error_free(&err); } else handle_modem_state(reply); dbus_message_unref(reply); } static DBusHandlerResult signal_filter(DBusConnection *conn, DBusMessage *msg, void *data) { const char *path = dbus_message_get_path(msg); if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming")) handle_incoming_call(msg); else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created")) handle_outgoing_call(msg); else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "CreateRequested")) handle_create_requested(msg); else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus")) handle_call_status(msg, path); else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined")) handle_conference(msg, TRUE); else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left")) handle_conference(msg, FALSE); else if (dbus_message_is_signal(msg, NETWORK_INTERFACE, "registration_status_change")) handle_registration_status_change(msg); else if (dbus_message_is_signal(msg, NETWORK_INTERFACE, "signal_strength_change")) handle_signal_strength_change(msg); else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device", "PropertyModified")) handle_hal_property_modified(msg); else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE, "modem_state_changed_ind")) handle_modem_state(msg); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } int telephony_init(void) { const char *battery_cap = "battery"; uint32_t features = AG_FEATURE_EC_ANDOR_NR | AG_FEATURE_INBAND_RINGTONE | AG_FEATURE_REJECT_A_CALL | AG_FEATURE_ENHANCED_CALL_STATUS | AG_FEATURE_ENHANCED_CALL_CONTROL | AG_FEATURE_EXTENDED_ERROR_RESULT_CODES | AG_FEATURE_THREE_WAY_CALLING; connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); if (!dbus_connection_add_filter(connection, signal_filter, NULL, NULL)) error("Can't add signal filter"); dbus_bus_add_match(connection, "type=signal,interface=" CSD_CALL_INTERFACE, NULL); dbus_bus_add_match(connection, "type=signal,interface=" CSD_CALL_INSTANCE, NULL); dbus_bus_add_match(connection, "type=signal,interface=" CSD_CALL_CONFERENCE, NULL); dbus_bus_add_match(connection, "type=signal,interface=" NETWORK_INTERFACE, NULL); dbus_bus_add_match(connection, "type=signal,interface=" SSC_DBUS_IFACE ",member=modem_state_changed_ind", NULL); if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE, "get_modem_state", modem_state_reply, NULL, DBUS_TYPE_INVALID) < 0) error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()"); generate_flag_file(NONE_FLAG_FILE); callerid = callerid_from_file(); if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH, TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods, NULL, NULL, NULL, NULL)) { error("telephony-maemo interface %s init failed on path %s", TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH); } DBG("telephony-maemo registering %s interface on path %s", TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH); telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED, chld_str); if (send_method_call("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager", "FindDeviceByCapability", hal_find_device_reply, NULL, DBUS_TYPE_STRING, &battery_cap, DBUS_TYPE_INVALID) < 0) error("Unable to send HAL method call"); return 0; } void telephony_exit(void) { g_slist_foreach(calls, (GFunc) csd_call_free, NULL); g_slist_free(calls); calls = NULL; dbus_connection_remove_filter(connection, signal_filter, NULL); dbus_connection_unref(connection); connection = NULL; telephony_deinit(); } bluez-4.101/audio/sink.c0000644000000000000000000004163711766125764011772 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "log.h" #include "device.h" #include "avdtp.h" #include "media.h" #include "a2dp.h" #include "error.h" #include "sink.h" #include "dbus-common.h" #include "../src/adapter.h" #include "../src/device.h" #define STREAM_SETUP_RETRY_TIMER 2 struct pending_request { DBusConnection *conn; DBusMessage *msg; unsigned int id; }; struct sink { struct audio_device *dev; struct avdtp *session; struct avdtp_stream *stream; unsigned int cb_id; guint retry_id; avdtp_session_state_t session_state; avdtp_state_t stream_state; sink_state_t state; struct pending_request *connect; struct pending_request *disconnect; DBusConnection *conn; }; struct sink_state_callback { sink_state_cb cb; void *user_data; unsigned int id; }; static GSList *sink_callbacks = NULL; static unsigned int avdtp_callback_id = 0; static char *str_state[] = { "SINK_STATE_DISCONNECTED", "SINK_STATE_CONNECTING", "SINK_STATE_CONNECTED", "SINK_STATE_PLAYING", }; static const char *state2str(sink_state_t state) { switch (state) { case SINK_STATE_DISCONNECTED: return "disconnected"; case SINK_STATE_CONNECTING: return "connecting"; case SINK_STATE_CONNECTED: return "connected"; case SINK_STATE_PLAYING: return "playing"; default: error("Invalid sink state %d", state); return NULL; } } static void sink_set_state(struct audio_device *dev, sink_state_t new_state) { struct sink *sink = dev->sink; const char *state_str; sink_state_t old_state = sink->state; GSList *l; sink->state = new_state; state_str = state2str(new_state); if (state_str) emit_property_changed(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "State", DBUS_TYPE_STRING, &state_str); DBG("State changed %s: %s -> %s", dev->path, str_state[old_state], str_state[new_state]); for (l = sink_callbacks; l != NULL; l = l->next) { struct sink_state_callback *cb = l->data; cb->cb(dev, old_state, new_state, cb->user_data); } } static void avdtp_state_callback(struct audio_device *dev, struct avdtp *session, avdtp_session_state_t old_state, avdtp_session_state_t new_state, void *user_data) { struct sink *sink = dev->sink; if (sink == NULL) return; switch (new_state) { case AVDTP_SESSION_STATE_DISCONNECTED: if (sink->state != SINK_STATE_CONNECTING) { gboolean value = FALSE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "Disconnected", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &value); } sink_set_state(dev, SINK_STATE_DISCONNECTED); break; case AVDTP_SESSION_STATE_CONNECTING: sink_set_state(dev, SINK_STATE_CONNECTING); break; case AVDTP_SESSION_STATE_CONNECTED: break; } sink->session_state = new_state; } static void pending_request_free(struct audio_device *dev, struct pending_request *pending) { if (pending->conn) dbus_connection_unref(pending->conn); if (pending->msg) dbus_message_unref(pending->msg); if (pending->id) a2dp_cancel(dev, pending->id); g_free(pending); } 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 audio_device *dev = user_data; struct sink *sink = dev->sink; gboolean value; if (err) return; switch (new_state) { case AVDTP_STATE_IDLE: if (sink->disconnect) { DBusMessage *reply; struct pending_request *p; p = sink->disconnect; sink->disconnect = NULL; reply = dbus_message_new_method_return(p->msg); g_dbus_send_message(p->conn, reply); pending_request_free(dev, p); } if (sink->session) { avdtp_unref(sink->session); sink->session = NULL; } sink->stream = NULL; sink->cb_id = 0; break; case AVDTP_STATE_OPEN: if (old_state == AVDTP_STATE_CONFIGURED && sink->state == SINK_STATE_CONNECTING) { value = TRUE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "Connected", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &value); } else if (old_state == AVDTP_STATE_STREAMING) { value = FALSE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "Stopped", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "Playing", DBUS_TYPE_BOOLEAN, &value); } sink_set_state(dev, SINK_STATE_CONNECTED); break; case AVDTP_STATE_STREAMING: value = TRUE; g_dbus_emit_signal(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "Playing", DBUS_TYPE_INVALID); emit_property_changed(dev->conn, dev->path, AUDIO_SINK_INTERFACE, "Playing", DBUS_TYPE_BOOLEAN, &value); sink_set_state(dev, SINK_STATE_PLAYING); break; case AVDTP_STATE_CONFIGURED: case AVDTP_STATE_CLOSING: case AVDTP_STATE_ABORTING: default: break; } sink->stream_state = new_state; } static void error_failed(DBusConnection *conn, DBusMessage *msg, const char *desc) { DBusMessage *reply = btd_error_failed(msg, desc); g_dbus_send_message(conn, reply); } static gboolean stream_setup_retry(gpointer user_data) { struct sink *sink = user_data; struct pending_request *pending = sink->connect; sink->retry_id = 0; if (sink->stream_state >= AVDTP_STATE_OPEN) { DBG("Stream successfully created, after XCASE connect:connect"); if (pending->msg) { DBusMessage *reply; reply = dbus_message_new_method_return(pending->msg); g_dbus_send_message(pending->conn, reply); } } else { DBG("Stream setup failed, after XCASE connect:connect"); if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); } sink->connect = NULL; pending_request_free(sink->dev, pending); return FALSE; } static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep, struct avdtp_stream *stream, struct avdtp_error *err, void *user_data) { struct sink *sink = user_data; struct pending_request *pending; pending = sink->connect; pending->id = 0; if (stream) { DBG("Stream successfully created"); if (pending->msg) { DBusMessage *reply; reply = dbus_message_new_method_return(pending->msg); g_dbus_send_message(pending->conn, reply); } sink->connect = NULL; pending_request_free(sink->dev, pending); return; } avdtp_unref(sink->session); sink->session = NULL; if (avdtp_error_category(err) == AVDTP_ERRNO && avdtp_error_posix_errno(err) != EHOSTDOWN) { DBG("connect:connect XCASE detected"); sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER, stream_setup_retry, sink); } else { if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); sink->connect = NULL; pending_request_free(sink->dev, pending); DBG("Stream setup failed : %s", avdtp_strerror(err)); } } static void select_complete(struct avdtp *session, struct a2dp_sep *sep, GSList *caps, void *user_data) { struct sink *sink = user_data; struct pending_request *pending; int id; pending = sink->connect; pending->id = 0; id = a2dp_config(session, sep, stream_setup_complete, caps, sink); if (id == 0) goto failed; pending->id = id; return; failed: if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); pending_request_free(sink->dev, pending); sink->connect = NULL; avdtp_unref(sink->session); sink->session = NULL; } static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err, void *user_data) { struct sink *sink = user_data; struct pending_request *pending; int id; if (!sink->connect) { avdtp_unref(sink->session); sink->session = NULL; return; } pending = sink->connect; if (err) { avdtp_unref(sink->session); sink->session = NULL; if (avdtp_error_category(err) == AVDTP_ERRNO && avdtp_error_posix_errno(err) != EHOSTDOWN) { DBG("connect:connect XCASE detected"); sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER, stream_setup_retry, sink); } else goto failed; return; } DBG("Discovery complete"); id = a2dp_select_capabilities(sink->session, AVDTP_SEP_TYPE_SINK, NULL, select_complete, sink); if (id == 0) goto failed; pending->id = id; return; failed: if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); pending_request_free(sink->dev, pending); sink->connect = NULL; avdtp_unref(sink->session); sink->session = NULL; } gboolean sink_setup_stream(struct sink *sink, struct avdtp *session) { if (sink->connect || sink->disconnect) return FALSE; if (session && !sink->session) sink->session = avdtp_ref(session); if (!sink->session) return FALSE; avdtp_set_auto_disconnect(sink->session, FALSE); if (avdtp_discover(sink->session, discovery_complete, sink) < 0) return FALSE; sink->connect = g_new0(struct pending_request, 1); return TRUE; } static DBusMessage *sink_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct sink *sink = dev->sink; struct pending_request *pending; if (!sink->session) sink->session = avdtp_get(&dev->src, &dev->dst); if (!sink->session) return btd_error_failed(msg, "Unable to get a session"); if (sink->connect || sink->disconnect) return btd_error_busy(msg); if (sink->stream_state >= AVDTP_STATE_OPEN) return btd_error_already_connected(msg); if (!sink_setup_stream(sink, NULL)) return btd_error_failed(msg, "Failed to create a stream"); dev->auto_connect = FALSE; pending = sink->connect; pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); DBG("stream creation in progress"); return NULL; } static DBusMessage *sink_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct sink *sink = device->sink; struct pending_request *pending; int err; if (!sink->session) return btd_error_not_connected(msg); if (sink->connect || sink->disconnect) return btd_error_busy(msg); if (sink->stream_state < AVDTP_STATE_OPEN) { DBusMessage *reply = dbus_message_new_method_return(msg); if (!reply) return NULL; avdtp_unref(sink->session); sink->session = NULL; return reply; } err = avdtp_close(sink->session, sink->stream, FALSE); if (err < 0) return btd_error_failed(msg, strerror(-err)); pending = g_new0(struct pending_request, 1); pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); sink->disconnect = pending; return NULL; } static DBusMessage *sink_is_connected(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct sink *sink = device->sink; DBusMessage *reply; dbus_bool_t connected; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; connected = (sink->stream_state >= AVDTP_STATE_CONFIGURED); dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected, DBUS_TYPE_INVALID); return reply; } static DBusMessage *sink_get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct sink *sink = device->sink; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; const char *state; gboolean value; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Playing */ value = (sink->stream_state == AVDTP_STATE_STREAMING); dict_append_entry(&dict, "Playing", DBUS_TYPE_BOOLEAN, &value); /* Connected */ value = (sink->stream_state >= AVDTP_STATE_CONFIGURED); dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value); /* State */ state = state2str(sink->state); if (state) dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state); dbus_message_iter_close_container(&iter, &dict); return reply; } static const GDBusMethodTable sink_methods[] = { { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, sink_connect) }, { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, sink_disconnect) }, { GDBUS_DEPRECATED_METHOD("IsConnected", NULL, GDBUS_ARGS({ "connected", "b" }), sink_is_connected) }, { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), sink_get_properties) }, { } }; static const GDBusSignalTable sink_signals[] = { { GDBUS_DEPRECATED_SIGNAL("Connected", NULL) }, { GDBUS_DEPRECATED_SIGNAL("Disconnected", NULL) }, { GDBUS_DEPRECATED_SIGNAL("Playing", NULL) }, { GDBUS_DEPRECATED_SIGNAL("Stopped", NULL) }, { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { } }; static void sink_free(struct audio_device *dev) { struct sink *sink = dev->sink; if (sink->cb_id) avdtp_stream_remove_cb(sink->session, sink->stream, sink->cb_id); if (sink->session) avdtp_unref(sink->session); if (sink->connect) pending_request_free(dev, sink->connect); if (sink->disconnect) pending_request_free(dev, sink->disconnect); if (sink->retry_id) g_source_remove(sink->retry_id); g_free(sink); dev->sink = NULL; } static void path_unregister(void *data) { struct audio_device *dev = data; DBG("Unregistered interface %s on path %s", AUDIO_SINK_INTERFACE, dev->path); sink_free(dev); } void sink_unregister(struct audio_device *dev) { g_dbus_unregister_interface(dev->conn, dev->path, AUDIO_SINK_INTERFACE); } struct sink *sink_init(struct audio_device *dev) { struct sink *sink; if (!g_dbus_register_interface(dev->conn, dev->path, AUDIO_SINK_INTERFACE, sink_methods, sink_signals, NULL, dev, path_unregister)) return NULL; DBG("Registered interface %s on path %s", AUDIO_SINK_INTERFACE, dev->path); if (avdtp_callback_id == 0) avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback, NULL); sink = g_new0(struct sink, 1); sink->dev = dev; return sink; } gboolean sink_is_active(struct audio_device *dev) { struct sink *sink = dev->sink; if (sink->session) return TRUE; return FALSE; } sink_state_t sink_get_state(struct audio_device *dev) { struct sink *sink = dev->sink; return sink->state; } gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session, struct avdtp_stream *stream) { struct sink *sink = dev->sink; if (sink->stream) return FALSE; if (!sink->session) sink->session = avdtp_ref(session); sink->stream = stream; sink->cb_id = avdtp_stream_add_cb(session, stream, stream_state_changed, dev); return TRUE; } gboolean sink_shutdown(struct sink *sink) { if (!sink->session) return FALSE; avdtp_set_device_disconnect(sink->session, TRUE); /* cancel pending connect */ if (sink->connect) { struct pending_request *pending = sink->connect; if (pending->msg) error_failed(pending->conn, pending->msg, "Stream setup failed"); pending_request_free(sink->dev, pending); sink->connect = NULL; avdtp_unref(sink->session); sink->session = NULL; return TRUE; } /* disconnect already ongoing */ if (sink->disconnect) return TRUE; if (!sink->stream) return FALSE; if (avdtp_close(sink->session, sink->stream, FALSE) < 0) return FALSE; return TRUE; } unsigned int sink_add_state_cb(sink_state_cb cb, void *user_data) { struct sink_state_callback *state_cb; static unsigned int id = 0; state_cb = g_new(struct sink_state_callback, 1); state_cb->cb = cb; state_cb->user_data = user_data; state_cb->id = ++id; sink_callbacks = g_slist_append(sink_callbacks, state_cb); return state_cb->id; } gboolean sink_remove_state_cb(unsigned int id) { GSList *l; for (l = sink_callbacks; l != NULL; l = l->next) { struct sink_state_callback *cb = l->data; if (cb && cb->id == id) { sink_callbacks = g_slist_remove(sink_callbacks, cb); g_free(cb); return TRUE; } } return FALSE; } bluez-4.101/audio/avctp.h0000644000000000000000000000650411766125764012142 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define AVCTP_PSM 23 #define AVC_MTU 512 #define AVC_HEADER_LENGTH 3 /* ctype entries */ #define AVC_CTYPE_CONTROL 0x0 #define AVC_CTYPE_STATUS 0x1 #define AVC_CTYPE_NOTIFY 0x3 #define AVC_CTYPE_NOT_IMPLEMENTED 0x8 #define AVC_CTYPE_ACCEPTED 0x9 #define AVC_CTYPE_REJECTED 0xA #define AVC_CTYPE_STABLE 0xC #define AVC_CTYPE_CHANGED 0xD #define AVC_CTYPE_INTERIM 0xF /* opcodes */ #define AVC_OP_VENDORDEP 0x00 #define AVC_OP_UNITINFO 0x30 #define AVC_OP_SUBUNITINFO 0x31 #define AVC_OP_PASSTHROUGH 0x7c /* subunits of interest */ #define AVC_SUBUNIT_PANEL 0x09 /* operands in passthrough commands */ #define VOL_UP_OP 0x41 #define VOL_DOWN_OP 0x42 #define MUTE_OP 0x43 #define PLAY_OP 0x44 #define STAVC_OP_OP 0x45 #define PAUSE_OP 0x46 #define RECORD_OP 0x47 #define REWIND_OP 0x48 #define FAST_FORWARD_OP 0x49 #define EJECT_OP 0x4a #define FORWARD_OP 0x4b #define BACKWARD_OP 0x4c struct avctp; typedef enum { AVCTP_STATE_DISCONNECTED = 0, AVCTP_STATE_CONNECTING, AVCTP_STATE_CONNECTED } avctp_state_t; typedef void (*avctp_state_cb) (struct audio_device *dev, avctp_state_t old_state, avctp_state_t new_state, void *user_data); typedef size_t (*avctp_pdu_cb) (struct avctp *session, uint8_t transaction, uint8_t *code, uint8_t *subunit, uint8_t *operands, size_t operand_count, void *user_data); typedef gboolean (*avctp_rsp_cb) (struct avctp *session, uint8_t code, uint8_t subunit, uint8_t *operands, size_t operand_count, void *user_data); unsigned int avctp_add_state_cb(avctp_state_cb cb, void *user_data); gboolean avctp_remove_state_cb(unsigned int id); int avctp_register(const bdaddr_t *src, gboolean master); void avctp_unregister(const bdaddr_t *src); struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst); struct avctp *avctp_get(const bdaddr_t *src, const bdaddr_t *dst); void avctp_disconnect(struct avctp *session); unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_pdu_cb cb, void *user_data); gboolean avctp_unregister_pdu_handler(unsigned int id); int avctp_send_passthrough(struct avctp *session, uint8_t op); int avctp_send_vendordep(struct avctp *session, uint8_t transaction, uint8_t code, uint8_t subunit, uint8_t *operands, size_t operand_count); int avctp_send_vendordep_req(struct avctp *session, uint8_t code, uint8_t subunit, uint8_t *operands, size_t operand_count, avctp_rsp_cb func, void *user_data); bluez-4.101/audio/gstavdtpsink.h0000644000000000000000000000534711571052274013537 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __GST_AVDTP_SINK_H #define __GST_AVDTP_SINK_H #include #include G_BEGIN_DECLS #define GST_TYPE_AVDTP_SINK \ (gst_avdtp_sink_get_type()) #define GST_AVDTP_SINK(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVDTP_SINK,\ GstAvdtpSink)) #define GST_AVDTP_SINK_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVDTP_SINK,\ GstAvdtpSinkClass)) #define GST_IS_AVDTP_SINK(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVDTP_SINK)) #define GST_IS_AVDTP_SINK_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVDTP_SINK)) typedef struct _GstAvdtpSink GstAvdtpSink; typedef struct _GstAvdtpSinkClass GstAvdtpSinkClass; struct bluetooth_data; struct _GstAvdtpSink { GstBaseSink sink; gchar *device; gchar *transport; GIOChannel *stream; struct bluetooth_data *data; gboolean autoconnect; GIOChannel *server; /* mp3 stream data (outside caps data)*/ gint mp3_using_crc; gint channel_mode; /* stream connection data */ GstCaps *stream_caps; GstCaps *dev_caps; GMutex *sink_lock; guint watch_id; }; struct _GstAvdtpSinkClass { GstBaseSinkClass parent_class; }; GType gst_avdtp_sink_get_type(void); GstCaps *gst_avdtp_sink_get_device_caps(GstAvdtpSink *sink); gboolean gst_avdtp_sink_set_device_caps(GstAvdtpSink *sink, GstCaps *caps); guint gst_avdtp_sink_get_link_mtu(GstAvdtpSink *sink); void gst_avdtp_sink_set_device(GstAvdtpSink *sink, const gchar* device); void gst_avdtp_sink_set_transport(GstAvdtpSink *sink, const gchar *transport); gchar *gst_avdtp_sink_get_device(GstAvdtpSink *sink); gchar *gst_avdtp_sink_get_transport(GstAvdtpSink *sink); gboolean gst_avdtp_sink_plugin_init(GstPlugin *plugin); void gst_avdtp_sink_set_crc(GstAvdtpSink *self, gboolean crc); void gst_avdtp_sink_set_channel_mode(GstAvdtpSink *self, const gchar *mode); G_END_DECLS #endif /* __GST_AVDTP_SINK_H */ bluez-4.101/audio/telephony-ofono.c0000644000000000000000000011625111766125764014146 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2009-2010 Intel Corporation * Copyright (C) 2006-2009 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "log.h" #include "telephony.h" enum net_registration_status { NETWORK_REG_STATUS_HOME = 0x00, NETWORK_REG_STATUS_ROAM, NETWORK_REG_STATUS_NOSERV }; struct voice_call { char *obj_path; int status; gboolean originating; gboolean conference; char *number; guint watch; }; static DBusConnection *connection = NULL; static char *modem_obj_path = NULL; static char *last_dialed_number = NULL; static GSList *calls = NULL; static GSList *watches = NULL; static GSList *pending = NULL; #define OFONO_BUS_NAME "org.ofono" #define OFONO_PATH "/" #define OFONO_MODEM_INTERFACE "org.ofono.Modem" #define OFONO_MANAGER_INTERFACE "org.ofono.Manager" #define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration" #define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager" #define OFONO_VC_INTERFACE "org.ofono.VoiceCall" /* HAL battery namespace key values */ static int battchg_cur = -1; /* "battery.charge_level.current" */ static int battchg_last = -1; /* "battery.charge_level.last_full" */ static int battchg_design = -1; /* "battery.charge_level.design" */ static struct { uint8_t status; uint32_t signals_bar; char *operator_name; } net = { .status = NETWORK_REG_STATUS_NOSERV, .signals_bar = 0, .operator_name = NULL, }; static const char *chld_str = "0,1,1x,2,2x,3,4"; static char *subscriber_number = NULL; static gboolean events_enabled = FALSE; static struct indicator ofono_indicators[] = { { "battchg", "0-5", 5, TRUE }, { "signal", "0-5", 5, TRUE }, { "service", "0,1", 1, TRUE }, { "call", "0,1", 0, TRUE }, { "callsetup", "0-3", 0, TRUE }, { "callheld", "0-2", 0, FALSE }, { "roam", "0,1", 0, TRUE }, { NULL } }; static struct voice_call *find_vc(const char *path) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct voice_call *vc = l->data; if (g_str_equal(vc->obj_path, path)) return vc; } return NULL; } static struct voice_call *find_vc_with_status(int status) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct voice_call *vc = l->data; if (vc->status == status) return vc; } return NULL; } static struct voice_call *find_vc_without_status(int status) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct voice_call *call = l->data; if (call->status != status) return call; } return NULL; } static int number_type(const char *number) { if (number == NULL) return NUMBER_TYPE_TELEPHONY; if (number[0] == '+' || strncmp(number, "00", 2) == 0) return NUMBER_TYPE_INTERNATIONAL; return NUMBER_TYPE_TELEPHONY; } void telephony_device_connected(void *telephony_device) { struct voice_call *coming; DBG("telephony-ofono: device %p connected", telephony_device); coming = find_vc_with_status(CALL_STATUS_ALERTING); if (coming) { if (find_vc_with_status(CALL_STATUS_ACTIVE)) telephony_call_waiting_ind(coming->number, number_type(coming->number)); else telephony_incoming_call_ind(coming->number, number_type(coming->number)); } } void telephony_device_disconnected(void *telephony_device) { DBG("telephony-ofono: device %p disconnected", telephony_device); events_enabled = FALSE; } void telephony_event_reporting_req(void *telephony_device, int ind) { events_enabled = ind == 1 ? TRUE : FALSE; telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE); } void telephony_response_and_hold_req(void *telephony_device, int rh) { telephony_response_and_hold_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED); } void telephony_last_dialed_number_req(void *telephony_device) { DBG("telephony-ofono: last dialed number request"); if (last_dialed_number) telephony_dial_number_req(telephony_device, last_dialed_number); else telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NOT_ALLOWED); } static int send_method_call(const char *dest, const char *path, const char *interface, const char *method, DBusPendingCallNotifyFunction cb, void *user_data, int type, ...) { DBusMessage *msg; DBusPendingCall *call; va_list args; msg = dbus_message_new_method_call(dest, path, interface, method); if (!msg) { error("Unable to allocate new D-Bus %s message", method); return -ENOMEM; } va_start(args, type); if (!dbus_message_append_args_valist(msg, type, args)) { dbus_message_unref(msg); va_end(args); return -EIO; } va_end(args); if (!cb) { g_dbus_send_message(connection, msg); return 0; } if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) { error("Sending %s failed", method); dbus_message_unref(msg); return -EIO; } dbus_pending_call_set_notify(call, cb, user_data, NULL); pending = g_slist_prepend(pending, call); dbus_message_unref(msg); return 0; } static int answer_call(struct voice_call *vc) { DBG("%s", vc->number); return send_method_call(OFONO_BUS_NAME, vc->obj_path, OFONO_VC_INTERFACE, "Answer", NULL, NULL, DBUS_TYPE_INVALID); } static int release_call(struct voice_call *vc) { DBG("%s", vc->number); return send_method_call(OFONO_BUS_NAME, vc->obj_path, OFONO_VC_INTERFACE, "Hangup", NULL, NULL, DBUS_TYPE_INVALID); } static int release_answer_calls(void) { DBG(""); return send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "ReleaseAndAnswer", NULL, NULL, DBUS_TYPE_INVALID); } static int split_call(struct voice_call *call) { DBG("%s", call->number); return send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "PrivateChat", NULL, NULL, DBUS_TYPE_OBJECT_PATH, call->obj_path, DBUS_TYPE_INVALID); return -1; } static int swap_calls(void) { DBG(""); return send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "SwapCalls", NULL, NULL, DBUS_TYPE_INVALID); } static int create_conference(void) { DBG(""); return send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "CreateMultiparty", NULL, NULL, DBUS_TYPE_INVALID); } static int release_conference(void) { DBG(""); return send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "HangupMultiparty", NULL, NULL, DBUS_TYPE_INVALID); } static int call_transfer(void) { DBG(""); return send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "Transfer", NULL, NULL, DBUS_TYPE_INVALID); } void telephony_terminate_call_req(void *telephony_device) { struct voice_call *call; struct voice_call *alerting; int err; call = find_vc_with_status(CALL_STATUS_ACTIVE); if (!call) call = calls->data; if (!call) { error("No active call"); telephony_terminate_call_rsp(telephony_device, CME_ERROR_NOT_ALLOWED); return; } alerting = find_vc_with_status(CALL_STATUS_ALERTING); if (call->status == CALL_STATUS_HELD && alerting) err = release_call(alerting); else if (call->conference) err = release_conference(); else err = release_call(call); if (err < 0) telephony_terminate_call_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE); } void telephony_answer_call_req(void *telephony_device) { struct voice_call *vc; int ret; vc = find_vc_with_status(CALL_STATUS_INCOMING); if (!vc) vc = find_vc_with_status(CALL_STATUS_ALERTING); if (!vc) vc = find_vc_with_status(CALL_STATUS_WAITING); if (!vc) { telephony_answer_call_rsp(telephony_device, CME_ERROR_NOT_ALLOWED); return; } ret = answer_call(vc); if (ret < 0) { telephony_answer_call_rsp(telephony_device, CME_ERROR_AG_FAILURE); return; } telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE); } void telephony_dial_number_req(void *telephony_device, const char *number) { const char *clir; int ret; DBG("telephony-ofono: dial request to %s", number); if (!modem_obj_path) { telephony_dial_number_rsp(telephony_device, CME_ERROR_AG_FAILURE); return; } if (!strncmp(number, "*31#", 4)) { number += 4; clir = "enabled"; } else if (!strncmp(number, "#31#", 4)) { number += 4; clir = "disabled"; } else clir = "default"; ret = send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "Dial", NULL, NULL, DBUS_TYPE_STRING, &number, DBUS_TYPE_STRING, &clir, DBUS_TYPE_INVALID); if (ret < 0) telephony_dial_number_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE); } void telephony_transmit_dtmf_req(void *telephony_device, char tone) { char *tone_string; int ret; DBG("telephony-ofono: transmit dtmf: %c", tone); if (!modem_obj_path) { telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_AG_FAILURE); return; } tone_string = g_strdup_printf("%c", tone); ret = send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "SendTones", NULL, NULL, DBUS_TYPE_STRING, &tone_string, DBUS_TYPE_INVALID); g_free(tone_string); if (ret < 0) telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE); } void telephony_subscriber_number_req(void *telephony_device) { DBG("telephony-ofono: subscriber number request"); if (subscriber_number) telephony_subscriber_number_ind(subscriber_number, NUMBER_TYPE_TELEPHONY, SUBSCRIBER_SERVICE_VOICE); telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE); } void telephony_list_current_calls_req(void *telephony_device) { GSList *l; int i; DBG("telephony-ofono: list current calls request"); for (l = calls, i = 1; l != NULL; l = l->next, i++) { struct voice_call *vc = l->data; int direction, multiparty; direction = vc->originating ? CALL_DIR_OUTGOING : CALL_DIR_INCOMING; multiparty = vc->conference ? CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO; DBG("call %s direction %d multiparty %d", vc->number, direction, multiparty); telephony_list_current_call_ind(i, direction, vc->status, CALL_MODE_VOICE, multiparty, vc->number, number_type(vc->number)); } telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE); } void telephony_operator_selection_req(void *telephony_device) { DBG("telephony-ofono: operator selection request"); telephony_operator_selection_ind(OPERATOR_MODE_AUTO, net.operator_name ? net.operator_name : ""); telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE); } static void foreach_vc_with_status(int status, int (*func)(struct voice_call *vc)) { GSList *l; for (l = calls; l != NULL; l = l->next) { struct voice_call *call = l->data; if (call->status == status) func(call); } } void telephony_call_hold_req(void *telephony_device, const char *cmd) { const char *idx; struct voice_call *call; int err = 0; DBG("telephony-ofono: got call hold request %s", cmd); if (strlen(cmd) > 1) idx = &cmd[1]; else idx = NULL; if (idx) call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1); else call = NULL; switch (cmd[0]) { case '0': if (find_vc_with_status(CALL_STATUS_WAITING)) foreach_vc_with_status(CALL_STATUS_WAITING, release_call); else foreach_vc_with_status(CALL_STATUS_HELD, release_call); break; case '1': if (idx) { if (call) err = release_call(call); break; } err = release_answer_calls(); break; case '2': if (idx) { if (call) err = split_call(call); } else { call = find_vc_with_status(CALL_STATUS_WAITING); if (call) err = answer_call(call); else err = swap_calls(); } break; case '3': if (find_vc_with_status(CALL_STATUS_HELD) || find_vc_with_status(CALL_STATUS_WAITING)) err = create_conference(); break; case '4': err = call_transfer(); break; default: DBG("Unknown call hold request"); break; } if (err) telephony_call_hold_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE); } void telephony_nr_and_ec_req(void *telephony_device, gboolean enable) { DBG("telephony-ofono: got %s NR and EC request", enable ? "enable" : "disable"); telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE); } void telephony_key_press_req(void *telephony_device, const char *keys) { struct voice_call *active, *incoming; int err; DBG("telephony-ofono: got key press request for %s", keys); incoming = find_vc_with_status(CALL_STATUS_INCOMING); active = find_vc_with_status(CALL_STATUS_ACTIVE); if (incoming) err = answer_call(incoming); else if (active) err = release_call(active); else err = 0; if (err < 0) telephony_key_press_rsp(telephony_device, CME_ERROR_AG_FAILURE); else telephony_key_press_rsp(telephony_device, CME_ERROR_NONE); } void telephony_voice_dial_req(void *telephony_device, gboolean enable) { DBG("telephony-ofono: got %s voice dial request", enable ? "enable" : "disable"); telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED); } static gboolean iter_get_basic_args(DBusMessageIter *iter, int first_arg_type, ...) { int type; va_list ap; va_start(ap, first_arg_type); for (type = first_arg_type; type != DBUS_TYPE_INVALID; type = va_arg(ap, int)) { void *value = va_arg(ap, void *); int real_type = dbus_message_iter_get_arg_type(iter); if (real_type != type) { error("iter_get_basic_args: expected %c but got %c", (char) type, (char) real_type); break; } dbus_message_iter_get_basic(iter, value); dbus_message_iter_next(iter); } va_end(ap); return type == DBUS_TYPE_INVALID ? TRUE : FALSE; } static void call_free(void *data) { struct voice_call *vc = data; DBG("%s", vc->obj_path); if (vc->status == CALL_STATUS_ACTIVE) telephony_update_indicator(ofono_indicators, "call", EV_CALL_INACTIVE); else telephony_update_indicator(ofono_indicators, "callsetup", EV_CALLSETUP_INACTIVE); if (vc->status == CALL_STATUS_INCOMING) telephony_calling_stopped_ind(); g_dbus_remove_watch(connection, vc->watch); g_free(vc->obj_path); g_free(vc->number); g_free(vc); } static gboolean handle_vc_property_changed(DBusConnection *conn, DBusMessage *msg, void *data) { struct voice_call *vc = data; const char *obj_path = dbus_message_get_path(msg); DBusMessageIter iter, sub; const char *property, *state; DBG("path %s", obj_path); dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { error("Unexpected signature in vc PropertyChanged signal"); return TRUE; } dbus_message_iter_get_basic(&iter, &property); DBG("property %s", property); dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &sub); if (g_str_equal(property, "State")) { dbus_message_iter_get_basic(&sub, &state); DBG("State %s", state); if (g_str_equal(state, "disconnected")) { calls = g_slist_remove(calls, vc); call_free(vc); } else if (g_str_equal(state, "active")) { telephony_update_indicator(ofono_indicators, "call", EV_CALL_ACTIVE); telephony_update_indicator(ofono_indicators, "callsetup", EV_CALLSETUP_INACTIVE); if (vc->status == CALL_STATUS_INCOMING) telephony_calling_stopped_ind(); vc->status = CALL_STATUS_ACTIVE; } else if (g_str_equal(state, "alerting")) { telephony_update_indicator(ofono_indicators, "callsetup", EV_CALLSETUP_ALERTING); vc->status = CALL_STATUS_ALERTING; vc->originating = TRUE; } else if (g_str_equal(state, "incoming")) { /* state change from waiting to incoming */ telephony_update_indicator(ofono_indicators, "callsetup", EV_CALLSETUP_INCOMING); telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY); vc->status = CALL_STATUS_INCOMING; vc->originating = FALSE; } else if (g_str_equal(state, "held")) { vc->status = CALL_STATUS_HELD; if (find_vc_without_status(CALL_STATUS_HELD)) telephony_update_indicator(ofono_indicators, "callheld", EV_CALLHELD_MULTIPLE); else telephony_update_indicator(ofono_indicators, "callheld", EV_CALLHELD_ON_HOLD); } } else if (g_str_equal(property, "Multiparty")) { dbus_bool_t multiparty; dbus_message_iter_get_basic(&sub, &multiparty); DBG("Multiparty %s", multiparty ? "True" : "False"); vc->conference = multiparty; } return TRUE; } static struct voice_call *call_new(const char *path, DBusMessageIter *properties) { struct voice_call *vc; DBG("%s", path); vc = g_new0(struct voice_call, 1); vc->obj_path = g_strdup(path); vc->watch = g_dbus_add_signal_watch(connection, NULL, path, OFONO_VC_INTERFACE, "PropertyChanged", handle_vc_property_changed, vc, NULL); while (dbus_message_iter_get_arg_type(properties) == DBUS_TYPE_DICT_ENTRY) { DBusMessageIter entry, value; const char *property, *cli, *state; dbus_bool_t multiparty; dbus_message_iter_recurse(properties, &entry); dbus_message_iter_get_basic(&entry, &property); dbus_message_iter_next(&entry); dbus_message_iter_recurse(&entry, &value); if (g_str_equal(property, "LineIdentification")) { dbus_message_iter_get_basic(&value, &cli); DBG("cli %s", cli); vc->number = g_strdup(cli); } else if (g_str_equal(property, "State")) { dbus_message_iter_get_basic(&value, &state); DBG("state %s", state); if (g_str_equal(state, "incoming")) vc->status = CALL_STATUS_INCOMING; else if (g_str_equal(state, "dialing")) vc->status = CALL_STATUS_DIALING; else if (g_str_equal(state, "alerting")) vc->status = CALL_STATUS_ALERTING; else if (g_str_equal(state, "waiting")) vc->status = CALL_STATUS_WAITING; else if (g_str_equal(state, "held")) vc->status = CALL_STATUS_HELD; } else if (g_str_equal(property, "Multiparty")) { dbus_message_iter_get_basic(&value, &multiparty); DBG("Multipary %s", multiparty ? "True" : "False"); vc->conference = multiparty; } dbus_message_iter_next(properties); } switch (vc->status) { case CALL_STATUS_INCOMING: DBG("CALL_STATUS_INCOMING"); vc->originating = FALSE; telephony_update_indicator(ofono_indicators, "callsetup", EV_CALLSETUP_INCOMING); telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY); break; case CALL_STATUS_DIALING: DBG("CALL_STATUS_DIALING"); vc->originating = TRUE; g_free(last_dialed_number); last_dialed_number = g_strdup(vc->number); telephony_update_indicator(ofono_indicators, "callsetup", EV_CALLSETUP_OUTGOING); break; case CALL_STATUS_ALERTING: DBG("CALL_STATUS_ALERTING"); vc->originating = TRUE; g_free(last_dialed_number); last_dialed_number = g_strdup(vc->number); telephony_update_indicator(ofono_indicators, "callsetup", EV_CALLSETUP_ALERTING); break; case CALL_STATUS_WAITING: DBG("CALL_STATUS_WAITING"); vc->originating = FALSE; telephony_update_indicator(ofono_indicators, "callsetup", EV_CALLSETUP_INCOMING); telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY); break; } return vc; } static void remove_pending(DBusPendingCall *call) { pending = g_slist_remove(pending, call); dbus_pending_call_unref(call); } static void call_added(const char *path, DBusMessageIter *properties) { struct voice_call *vc; DBG("%s", path); vc = find_vc(path); if (vc) return; vc = call_new(path, properties); calls = g_slist_prepend(calls, vc); } static void get_calls_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; DBusMessageIter iter, entry; DBG(""); reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("ofono replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature"); goto done; } dbus_message_iter_recurse(&iter, &entry); while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) { const char *path; DBusMessageIter value, properties; dbus_message_iter_recurse(&entry, &value); dbus_message_iter_get_basic(&value, &path); dbus_message_iter_next(&value); dbus_message_iter_recurse(&value, &properties); call_added(path, &properties); dbus_message_iter_next(&entry); } done: dbus_message_unref(reply); remove_pending(call); } static void handle_network_property(const char *property, DBusMessageIter *variant) { const char *status, *operator; unsigned int signals_bar; if (g_str_equal(property, "Status")) { dbus_message_iter_get_basic(variant, &status); DBG("Status is %s", status); if (g_str_equal(status, "registered")) { net.status = NETWORK_REG_STATUS_HOME; telephony_update_indicator(ofono_indicators, "roam", EV_ROAM_INACTIVE); telephony_update_indicator(ofono_indicators, "service", EV_SERVICE_PRESENT); } else if (g_str_equal(status, "roaming")) { net.status = NETWORK_REG_STATUS_ROAM; telephony_update_indicator(ofono_indicators, "roam", EV_ROAM_ACTIVE); telephony_update_indicator(ofono_indicators, "service", EV_SERVICE_PRESENT); } else { net.status = NETWORK_REG_STATUS_NOSERV; telephony_update_indicator(ofono_indicators, "roam", EV_ROAM_INACTIVE); telephony_update_indicator(ofono_indicators, "service", EV_SERVICE_NONE); } } else if (g_str_equal(property, "Name")) { dbus_message_iter_get_basic(variant, &operator); DBG("Operator is %s", operator); g_free(net.operator_name); net.operator_name = g_strdup(operator); } else if (g_str_equal(property, "SignalStrength")) { dbus_message_iter_get_basic(variant, &signals_bar); DBG("SignalStrength is %d", signals_bar); net.signals_bar = signals_bar; telephony_update_indicator(ofono_indicators, "signal", (signals_bar + 20) / 21); } } static int parse_network_properties(DBusMessageIter *properties) { int i; /* Reset indicators */ for (i = 0; ofono_indicators[i].desc != NULL; i++) { if (g_str_equal(ofono_indicators[i].desc, "battchg")) ofono_indicators[i].val = 5; else ofono_indicators[i].val = 0; } while (dbus_message_iter_get_arg_type(properties) == DBUS_TYPE_DICT_ENTRY) { const char *key; DBusMessageIter value, entry; dbus_message_iter_recurse(properties, &entry); dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); dbus_message_iter_recurse(&entry, &value); handle_network_property(key, &value); dbus_message_iter_next(properties); } return 0; } static void get_properties_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; DBusMessageIter iter, properties; int ret = 0; DBG(""); reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("ofono replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature"); goto done; } dbus_message_iter_recurse(&iter, &properties); ret = parse_network_properties(&properties); if (ret < 0) { error("Unable to parse %s.GetProperty reply", OFONO_NETWORKREG_INTERFACE); goto done; } ret = send_method_call(OFONO_BUS_NAME, modem_obj_path, OFONO_VCMANAGER_INTERFACE, "GetCalls", get_calls_reply, NULL, DBUS_TYPE_INVALID); if (ret < 0) error("Unable to send %s.GetCalls", OFONO_VCMANAGER_INTERFACE); done: dbus_message_unref(reply); remove_pending(call); } static void network_found(const char *path) { int ret; DBG("%s", path); modem_obj_path = g_strdup(path); ret = send_method_call(OFONO_BUS_NAME, path, OFONO_NETWORKREG_INTERFACE, "GetProperties", get_properties_reply, NULL, DBUS_TYPE_INVALID); if (ret < 0) error("Unable to send %s.GetProperties", OFONO_NETWORKREG_INTERFACE); } static void modem_removed(const char *path) { if (g_strcmp0(modem_obj_path, path) != 0) return; DBG("%s", path); g_slist_free_full(calls, call_free); calls = NULL; g_free(net.operator_name); net.operator_name = NULL; net.status = NETWORK_REG_STATUS_NOSERV; net.signals_bar = 0; g_free(modem_obj_path); modem_obj_path = NULL; } static void parse_modem_interfaces(const char *path, DBusMessageIter *ifaces) { DBG("%s", path); while (dbus_message_iter_get_arg_type(ifaces) == DBUS_TYPE_STRING) { const char *iface; dbus_message_iter_get_basic(ifaces, &iface); if (g_str_equal(iface, OFONO_NETWORKREG_INTERFACE)) { network_found(path); return; } dbus_message_iter_next(ifaces); } modem_removed(path); } static void modem_added(const char *path, DBusMessageIter *properties) { if (modem_obj_path != NULL) { DBG("Ignoring, modem already exist"); return; } DBG("%s", path); while (dbus_message_iter_get_arg_type(properties) == DBUS_TYPE_DICT_ENTRY) { const char *key; DBusMessageIter interfaces, value, entry; dbus_message_iter_recurse(properties, &entry); dbus_message_iter_get_basic(&entry, &key); dbus_message_iter_next(&entry); dbus_message_iter_recurse(&entry, &value); if (strcasecmp(key, "Interfaces") != 0) goto next; if (dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_ARRAY) { error("Invalid Signature"); return; } dbus_message_iter_recurse(&value, &interfaces); parse_modem_interfaces(path, &interfaces); if (modem_obj_path != NULL) return; next: dbus_message_iter_next(properties); } } static void get_modems_reply(DBusPendingCall *call, void *user_data) { DBusError err; DBusMessage *reply; DBusMessageIter iter, entry; DBG(""); reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("ofono replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } /* Skip modem selection if a modem already exist */ if (modem_obj_path != NULL) goto done; dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature"); goto done; } dbus_message_iter_recurse(&iter, &entry); while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRUCT) { const char *path; DBusMessageIter item, properties; dbus_message_iter_recurse(&entry, &item); dbus_message_iter_get_basic(&item, &path); dbus_message_iter_next(&item); dbus_message_iter_recurse(&item, &properties); modem_added(path, &properties); if (modem_obj_path != NULL) break; dbus_message_iter_next(&entry); } done: dbus_message_unref(reply); remove_pending(call); } static gboolean handle_network_property_changed(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter, variant; const char *property; dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { error("Unexpected signature in networkregistration" " PropertyChanged signal"); return TRUE; } dbus_message_iter_get_basic(&iter, &property); DBG("in handle_registration_property_changed()," " the property is %s", property); dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &variant); handle_network_property(property, &variant); return TRUE; } static void handle_modem_property(const char *path, const char *property, DBusMessageIter *variant) { DBG("%s", property); if (g_str_equal(property, "Interfaces")) { DBusMessageIter interfaces; if (dbus_message_iter_get_arg_type(variant) != DBUS_TYPE_ARRAY) { error("Invalid signature"); return; } dbus_message_iter_recurse(variant, &interfaces); parse_modem_interfaces(path, &interfaces); } } static gboolean handle_modem_property_changed(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter, variant; const char *property, *path; path = dbus_message_get_path(msg); /* Ignore if modem already exist and paths doesn't match */ if (modem_obj_path != NULL && g_str_equal(path, modem_obj_path) == FALSE) return TRUE; dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) { error("Unexpected signature in %s.%s PropertyChanged signal", dbus_message_get_interface(msg), dbus_message_get_member(msg)); return TRUE; } dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &variant); handle_modem_property(path, property, &variant); return TRUE; } static gboolean handle_vcmanager_call_added(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter, properties; const char *path = dbus_message_get_path(msg); /* Ignore call if modem path doesn't math */ if (g_strcmp0(modem_obj_path, path) != 0) return TRUE; dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) { error("Unexpected signature in %s.%s signal", dbus_message_get_interface(msg), dbus_message_get_member(msg)); return TRUE; } dbus_message_iter_get_basic(&iter, &path); dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &properties); call_added(path, &properties); return TRUE; } static void call_removed(const char *path) { struct voice_call *vc; DBG("%s", path); vc = find_vc(path); if (vc == NULL) return; calls = g_slist_remove(calls, vc); call_free(vc); } static gboolean handle_vcmanager_call_removed(DBusConnection *conn, DBusMessage *msg, void *data) { const char *path = dbus_message_get_path(msg); /* Ignore call if modem path doesn't math */ if (g_strcmp0(modem_obj_path, path) != 0) return TRUE; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { error("Unexpected signature in %s.%s signal", dbus_message_get_interface(msg), dbus_message_get_member(msg)); return TRUE; } call_removed(path); return TRUE; } static gboolean handle_manager_modem_added(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter, properties; const char *path; if (modem_obj_path != NULL) return TRUE; dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) { error("Unexpected signature in %s.%s signal", dbus_message_get_interface(msg), dbus_message_get_member(msg)); return TRUE; } dbus_message_iter_get_basic(&iter, &path); dbus_message_iter_next(&iter); dbus_message_iter_recurse(&iter, &properties); modem_added(path, &properties); return TRUE; } static gboolean handle_manager_modem_removed(DBusConnection *conn, DBusMessage *msg, void *data) { const char *path; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) { error("Unexpected signature in %s.%s signal", dbus_message_get_interface(msg), dbus_message_get_member(msg)); return TRUE; } modem_removed(path); return TRUE; } static void hal_battery_level_reply(DBusPendingCall *call, void *user_data) { DBusMessage *reply; DBusError err; dbus_int32_t level; int *value = user_data; reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("hald replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_error_init(&err); if (dbus_message_get_args(reply, &err, DBUS_TYPE_INT32, &level, DBUS_TYPE_INVALID) == FALSE) { error("Unable to parse GetPropertyInteger reply: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } *value = (int) level; if (value == &battchg_last) DBG("telephony-ofono: battery.charge_level.last_full" " is %d", *value); else if (value == &battchg_design) DBG("telephony-ofono: battery.charge_level.design" " is %d", *value); else DBG("telephony-ofono: battery.charge_level.current" " is %d", *value); if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) { int new, max; if (battchg_last > 0) max = battchg_last; else max = battchg_design; new = battchg_cur * 5 / max; telephony_update_indicator(ofono_indicators, "battchg", new); } done: dbus_message_unref(reply); remove_pending(call); } static void hal_get_integer(const char *path, const char *key, void *user_data) { send_method_call("org.freedesktop.Hal", path, "org.freedesktop.Hal.Device", "GetPropertyInteger", hal_battery_level_reply, user_data, DBUS_TYPE_STRING, &key, DBUS_TYPE_INVALID); } static gboolean handle_hal_property_modified(DBusConnection *conn, DBusMessage *msg, void *data) { const char *path; DBusMessageIter iter, array; dbus_int32_t num_changes; path = dbus_message_get_path(msg); dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) { error("Unexpected signature in hal PropertyModified signal"); return TRUE; } dbus_message_iter_get_basic(&iter, &num_changes); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature in hal PropertyModified signal"); return TRUE; } dbus_message_iter_recurse(&iter, &array); while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) { DBusMessageIter prop; const char *name; dbus_bool_t added, removed; dbus_message_iter_recurse(&array, &prop); if (!iter_get_basic_args(&prop, DBUS_TYPE_STRING, &name, DBUS_TYPE_BOOLEAN, &added, DBUS_TYPE_BOOLEAN, &removed, DBUS_TYPE_INVALID)) { error("Invalid hal PropertyModified parameters"); break; } if (g_str_equal(name, "battery.charge_level.last_full")) hal_get_integer(path, name, &battchg_last); else if (g_str_equal(name, "battery.charge_level.current")) hal_get_integer(path, name, &battchg_cur); else if (g_str_equal(name, "battery.charge_level.design")) hal_get_integer(path, name, &battchg_design); dbus_message_iter_next(&array); } return TRUE; } static void add_watch(const char *sender, const char *path, const char *interface, const char *member, GDBusSignalFunction function) { guint watch; watch = g_dbus_add_signal_watch(connection, sender, path, interface, member, function, NULL, NULL); watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch)); } static void hal_find_device_reply(DBusPendingCall *call, void *user_data) { DBusMessage *reply; DBusError err; DBusMessageIter iter, sub; int type; const char *path; DBG("begin of hal_find_device_reply()"); reply = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) { error("hald replied with an error: %s, %s", err.name, err.message); dbus_error_free(&err); goto done; } dbus_message_iter_init(reply, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) { error("Unexpected signature in hal_find_device_reply()"); goto done; } dbus_message_iter_recurse(&iter, &sub); type = dbus_message_iter_get_arg_type(&sub); if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) { error("No hal device with battery capability found"); goto done; } dbus_message_iter_get_basic(&sub, &path); DBG("telephony-ofono: found battery device at %s", path); add_watch(NULL, path, "org.freedesktop.Hal.Device", "PropertyModified", handle_hal_property_modified); hal_get_integer(path, "battery.charge_level.last_full", &battchg_last); hal_get_integer(path, "battery.charge_level.current", &battchg_cur); hal_get_integer(path, "battery.charge_level.design", &battchg_design); done: dbus_message_unref(reply); remove_pending(call); } static void handle_service_connect(DBusConnection *conn, void *user_data) { DBG("telephony-ofono: %s found", OFONO_BUS_NAME); send_method_call(OFONO_BUS_NAME, OFONO_PATH, OFONO_MANAGER_INTERFACE, "GetModems", get_modems_reply, NULL, DBUS_TYPE_INVALID); } static void handle_service_disconnect(DBusConnection *conn, void *user_data) { DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME); if (modem_obj_path) modem_removed(modem_obj_path); } int telephony_init(void) { uint32_t features = AG_FEATURE_EC_ANDOR_NR | AG_FEATURE_INBAND_RINGTONE | AG_FEATURE_REJECT_A_CALL | AG_FEATURE_ENHANCED_CALL_STATUS | AG_FEATURE_ENHANCED_CALL_CONTROL | AG_FEATURE_EXTENDED_ERROR_RESULT_CODES | AG_FEATURE_THREE_WAY_CALLING; const char *battery_cap = "battery"; int ret; guint watch; connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); add_watch(OFONO_BUS_NAME, NULL, OFONO_MODEM_INTERFACE, "PropertyChanged", handle_modem_property_changed); add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE, "PropertyChanged", handle_network_property_changed); add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE, "ModemAdded", handle_manager_modem_added); add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE, "ModemRemoved", handle_manager_modem_removed); add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE, "CallAdded", handle_vcmanager_call_added); add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE, "CallRemoved", handle_vcmanager_call_removed); watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME, handle_service_connect, handle_service_disconnect, NULL, NULL); if (watch == 0) return -ENOMEM; watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch)); ret = send_method_call("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager", "org.freedesktop.Hal.Manager", "FindDeviceByCapability", hal_find_device_reply, NULL, DBUS_TYPE_STRING, &battery_cap, DBUS_TYPE_INVALID); if (ret < 0) return ret; DBG("telephony_init() successfully"); telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED, chld_str); return ret; } static void remove_watch(gpointer data) { g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data)); } static void pending_free(void *data) { DBusPendingCall *call = data; if (!dbus_pending_call_get_completed(call)) dbus_pending_call_cancel(call); dbus_pending_call_unref(call); } void telephony_exit(void) { DBG(""); g_free(last_dialed_number); last_dialed_number = NULL; if (modem_obj_path) modem_removed(modem_obj_path); g_slist_free_full(watches, remove_watch); watches = NULL; g_slist_free_full(pending, pending_free); pending = NULL; dbus_connection_unref(connection); connection = NULL; telephony_deinit(); } bluez-4.101/audio/avdtp.c0000644000000000000000000027240711771117441012132 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "../src/adapter.h" #include "../src/manager.h" #include "../src/device.h" #include "device.h" #include "manager.h" #include "control.h" #include "avdtp.h" #include "btio.h" #include "sink.h" #include "source.h" #define AVDTP_PSM 25 #define MAX_SEID 0x3E #ifndef MAX # define MAX(x, y) ((x) > (y) ? (x) : (y)) #endif #define AVDTP_DISCOVER 0x01 #define AVDTP_GET_CAPABILITIES 0x02 #define AVDTP_SET_CONFIGURATION 0x03 #define AVDTP_GET_CONFIGURATION 0x04 #define AVDTP_RECONFIGURE 0x05 #define AVDTP_OPEN 0x06 #define AVDTP_START 0x07 #define AVDTP_CLOSE 0x08 #define AVDTP_SUSPEND 0x09 #define AVDTP_ABORT 0x0A #define AVDTP_SECURITY_CONTROL 0x0B #define AVDTP_GET_ALL_CAPABILITIES 0x0C #define AVDTP_DELAY_REPORT 0x0D #define AVDTP_PKT_TYPE_SINGLE 0x00 #define AVDTP_PKT_TYPE_START 0x01 #define AVDTP_PKT_TYPE_CONTINUE 0x02 #define AVDTP_PKT_TYPE_END 0x03 #define AVDTP_MSG_TYPE_COMMAND 0x00 #define AVDTP_MSG_TYPE_GEN_REJECT 0x01 #define AVDTP_MSG_TYPE_ACCEPT 0x02 #define AVDTP_MSG_TYPE_REJECT 0x03 #define REQ_TIMEOUT 6 #define ABORT_TIMEOUT 2 #define DISCONNECT_TIMEOUT 1 #define STREAM_TIMEOUT 20 #if __BYTE_ORDER == __LITTLE_ENDIAN struct avdtp_common_header { uint8_t message_type:2; uint8_t packet_type:2; uint8_t transaction:4; } __attribute__ ((packed)); struct avdtp_single_header { uint8_t message_type:2; uint8_t packet_type:2; uint8_t transaction:4; uint8_t signal_id:6; uint8_t rfa0:2; } __attribute__ ((packed)); struct avdtp_start_header { uint8_t message_type:2; uint8_t packet_type:2; uint8_t transaction:4; uint8_t no_of_packets; uint8_t signal_id:6; uint8_t rfa0:2; } __attribute__ ((packed)); struct avdtp_continue_header { uint8_t message_type:2; uint8_t packet_type:2; uint8_t transaction:4; } __attribute__ ((packed)); struct seid_info { uint8_t rfa0:1; uint8_t inuse:1; uint8_t seid:6; uint8_t rfa2:3; uint8_t type:1; uint8_t media_type:4; } __attribute__ ((packed)); struct seid { uint8_t rfa0:2; uint8_t seid:6; } __attribute__ ((packed)); #elif __BYTE_ORDER == __BIG_ENDIAN struct avdtp_common_header { uint8_t transaction:4; uint8_t packet_type:2; uint8_t message_type:2; } __attribute__ ((packed)); struct avdtp_single_header { uint8_t transaction:4; uint8_t packet_type:2; uint8_t message_type:2; uint8_t rfa0:2; uint8_t signal_id:6; } __attribute__ ((packed)); struct avdtp_start_header { uint8_t transaction:4; uint8_t packet_type:2; uint8_t message_type:2; uint8_t no_of_packets; uint8_t rfa0:2; uint8_t signal_id:6; } __attribute__ ((packed)); struct avdtp_continue_header { uint8_t transaction:4; uint8_t packet_type:2; uint8_t message_type:2; } __attribute__ ((packed)); struct seid_info { uint8_t seid:6; uint8_t inuse:1; uint8_t rfa0:1; uint8_t media_type:4; uint8_t type:1; uint8_t rfa2:3; } __attribute__ ((packed)); struct seid { uint8_t seid:6; uint8_t rfa0:2; } __attribute__ ((packed)); #else #error "Unknown byte order" #endif /* packets */ struct discover_resp { struct seid_info seps[0]; } __attribute__ ((packed)); struct getcap_resp { uint8_t caps[0]; } __attribute__ ((packed)); struct start_req { struct seid first_seid; struct seid other_seids[0]; } __attribute__ ((packed)); struct suspend_req { struct seid first_seid; struct seid other_seids[0]; } __attribute__ ((packed)); struct seid_rej { uint8_t error; } __attribute__ ((packed)); struct conf_rej { uint8_t category; uint8_t error; } __attribute__ ((packed)); #if __BYTE_ORDER == __LITTLE_ENDIAN struct seid_req { uint8_t rfa0:2; uint8_t acp_seid:6; } __attribute__ ((packed)); struct setconf_req { uint8_t rfa0:2; uint8_t acp_seid:6; uint8_t rfa1:2; uint8_t int_seid:6; uint8_t caps[0]; } __attribute__ ((packed)); struct stream_rej { uint8_t rfa0:2; uint8_t acp_seid:6; uint8_t error; } __attribute__ ((packed)); struct reconf_req { uint8_t rfa0:2; uint8_t acp_seid:6; uint8_t serv_cap; uint8_t serv_cap_len; uint8_t caps[0]; } __attribute__ ((packed)); struct delay_req { uint8_t rfa0:2; uint8_t acp_seid:6; uint16_t delay; } __attribute__ ((packed)); #elif __BYTE_ORDER == __BIG_ENDIAN struct seid_req { uint8_t acp_seid:6; uint8_t rfa0:2; } __attribute__ ((packed)); struct setconf_req { uint8_t acp_seid:6; uint8_t rfa0:2; uint8_t int_seid:6; uint8_t rfa1:2; uint8_t caps[0]; } __attribute__ ((packed)); struct stream_rej { uint8_t acp_seid:6; uint8_t rfa0:2; uint8_t error; } __attribute__ ((packed)); struct reconf_req { uint8_t acp_seid:6; uint8_t rfa0:2; uint8_t serv_cap; uint8_t serv_cap_len; uint8_t caps[0]; } __attribute__ ((packed)); struct delay_req { uint8_t acp_seid:6; uint8_t rfa0:2; uint16_t delay; } __attribute__ ((packed)); #else #error "Unknown byte order" #endif struct in_buf { gboolean active; int no_of_packets; uint8_t transaction; uint8_t message_type; uint8_t signal_id; uint8_t buf[1024]; uint8_t data_size; }; struct pending_req { uint8_t transaction; uint8_t signal_id; void *data; size_t data_size; struct avdtp_stream *stream; /* Set if the request targeted a stream */ guint timeout; gboolean collided; }; struct avdtp_remote_sep { uint8_t seid; uint8_t type; uint8_t media_type; struct avdtp_service_capability *codec; gboolean delay_reporting; GSList *caps; /* of type struct avdtp_service_capability */ struct avdtp_stream *stream; }; struct avdtp_server { bdaddr_t src; uint16_t version; GIOChannel *io; GSList *seps; GSList *sessions; }; struct avdtp_local_sep { avdtp_state_t state; struct avdtp_stream *stream; struct seid_info info; uint8_t codec; gboolean delay_reporting; GSList *caps; struct avdtp_sep_ind *ind; struct avdtp_sep_cfm *cfm; void *user_data; struct avdtp_server *server; }; struct stream_callback { avdtp_stream_state_cb cb; void *user_data; unsigned int id; }; struct avdtp_state_callback { avdtp_session_state_cb cb; void *user_data; unsigned int id; }; struct avdtp_stream { GIOChannel *io; uint16_t imtu; uint16_t omtu; struct avdtp *session; struct avdtp_local_sep *lsep; uint8_t rseid; GSList *caps; GSList *callbacks; struct avdtp_service_capability *codec; guint io_id; /* Transport GSource ID */ guint timer; /* Waiting for other side to close or open * the transport channel */ gboolean open_acp; /* If we are in ACT role for Open */ gboolean close_int; /* If we are in INT role for Close */ gboolean abort_int; /* If we are in INT role for Abort */ guint idle_timer; gboolean delay_reporting; uint16_t delay; /* AVDTP 1.3 Delay Reporting feature */ gboolean starting; /* only valid while sep state == OPEN */ }; /* Structure describing an AVDTP connection between two devices */ struct avdtp { int ref; int free_lock; uint16_t version; struct avdtp_server *server; bdaddr_t dst; avdtp_session_state_t state; /* True if the session should be automatically disconnected */ gboolean auto_dc; /* True if the entire device is being disconnected */ gboolean device_disconnect; GIOChannel *io; guint io_id; GSList *seps; /* Elements of type struct avdtp_remote_sep * */ GSList *streams; /* Elements of type struct avdtp_stream * */ GSList *req_queue; /* Elements of type struct pending_req * */ GSList *prio_queue; /* Same as req_queue but is processed before it */ struct avdtp_stream *pending_open; uint16_t imtu; uint16_t omtu; struct in_buf in; char *buf; avdtp_discover_cb_t discov_cb; void *user_data; struct pending_req *req; guint dc_timer; /* Attempt stream setup instead of disconnecting */ gboolean stream_setup; DBusPendingCall *pending_auth; }; static GSList *servers = NULL; static GSList *avdtp_callbacks = NULL; static gboolean auto_connect = TRUE; static int send_request(struct avdtp *session, gboolean priority, struct avdtp_stream *stream, uint8_t signal_id, void *buffer, size_t size); static gboolean avdtp_parse_resp(struct avdtp *session, struct avdtp_stream *stream, uint8_t transaction, uint8_t signal_id, void *buf, int size); static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stream, uint8_t transaction, uint8_t signal_id, void *buf, int size); static int process_queue(struct avdtp *session); static void connection_lost(struct avdtp *session, int err); static void avdtp_sep_set_state(struct avdtp *session, struct avdtp_local_sep *sep, avdtp_state_t state); static void auth_cb(DBusError *derr, void *user_data); static struct avdtp_server *find_server(GSList *list, const bdaddr_t *src) { for (; list; list = list->next) { struct avdtp_server *server = list->data; if (bacmp(&server->src, src) == 0) return server; } return NULL; } static const char *avdtp_statestr(avdtp_state_t state) { switch (state) { case AVDTP_STATE_IDLE: return "IDLE"; case AVDTP_STATE_CONFIGURED: return "CONFIGURED"; case AVDTP_STATE_OPEN: return "OPEN"; case AVDTP_STATE_STREAMING: return "STREAMING"; case AVDTP_STATE_CLOSING: return "CLOSING"; case AVDTP_STATE_ABORTING: return "ABORTING"; default: return ""; } } static gboolean try_send(int sk, void *data, size_t len) { int err; do { err = send(sk, data, len, 0); } while (err < 0 && errno == EINTR); if (err < 0) { error("send: %s (%d)", strerror(errno), errno); return FALSE; } else if ((size_t) err != len) { error("try_send: complete buffer not sent (%d/%zu bytes)", err, len); return FALSE; } return TRUE; } static gboolean avdtp_send(struct avdtp *session, uint8_t transaction, uint8_t message_type, uint8_t signal_id, void *data, size_t len) { unsigned int cont_fragments, sent; struct avdtp_start_header start; struct avdtp_continue_header cont; int sock; if (session->io == NULL) { error("avdtp_send: session is closed"); return FALSE; } sock = g_io_channel_unix_get_fd(session->io); /* Single packet - no fragmentation */ if (sizeof(struct avdtp_single_header) + len <= session->omtu) { struct avdtp_single_header single; memset(&single, 0, sizeof(single)); single.transaction = transaction; single.packet_type = AVDTP_PKT_TYPE_SINGLE; single.message_type = message_type; single.signal_id = signal_id; memcpy(session->buf, &single, sizeof(single)); memcpy(session->buf + sizeof(single), data, len); return try_send(sock, session->buf, sizeof(single) + len); } /* Check if there is enough space to start packet */ if (session->omtu < sizeof(start)) { error("No enough space to fragment packet"); return FALSE; } /* Count the number of needed fragments */ cont_fragments = (len - (session->omtu - sizeof(start))) / (session->omtu - sizeof(cont)) + 1; DBG("%zu bytes split into %d fragments", len, cont_fragments + 1); /* Send the start packet */ memset(&start, 0, sizeof(start)); start.transaction = transaction; start.packet_type = AVDTP_PKT_TYPE_START; start.message_type = message_type; start.no_of_packets = cont_fragments + 1; start.signal_id = signal_id; memcpy(session->buf, &start, sizeof(start)); memcpy(session->buf + sizeof(start), data, session->omtu - sizeof(start)); if (!try_send(sock, session->buf, session->omtu)) return FALSE; DBG("first packet with %zu bytes sent", session->omtu - sizeof(start)); sent = session->omtu - sizeof(start); /* Send the continue fragments and the end packet */ while (sent < len) { int left, to_copy; left = len - sent; if (left + sizeof(cont) > session->omtu) { cont.packet_type = AVDTP_PKT_TYPE_CONTINUE; to_copy = session->omtu - sizeof(cont); DBG("sending continue with %d bytes", to_copy); } else { cont.packet_type = AVDTP_PKT_TYPE_END; to_copy = left; DBG("sending end with %d bytes", to_copy); } cont.transaction = transaction; cont.message_type = message_type; memcpy(session->buf, &cont, sizeof(cont)); memcpy(session->buf + sizeof(cont), data + sent, to_copy); if (!try_send(sock, session->buf, to_copy + sizeof(cont))) return FALSE; sent += to_copy; } return TRUE; } static void pending_req_free(struct pending_req *req) { if (req->timeout) g_source_remove(req->timeout); g_free(req->data); g_free(req); } static void close_stream(struct avdtp_stream *stream) { int sock; if (stream->io == NULL) return; sock = g_io_channel_unix_get_fd(stream->io); shutdown(sock, SHUT_RDWR); g_io_channel_shutdown(stream->io, FALSE, NULL); g_io_channel_unref(stream->io); stream->io = NULL; } static gboolean stream_close_timeout(gpointer user_data) { struct avdtp_stream *stream = user_data; DBG("Timed out waiting for peer to close the transport channel"); stream->timer = 0; close_stream(stream); return FALSE; } static gboolean stream_open_timeout(gpointer user_data) { struct avdtp_stream *stream = user_data; DBG("Timed out waiting for peer to open the transport channel"); stream->timer = 0; stream->session->pending_open = NULL; avdtp_abort(stream->session, stream); return FALSE; } static gboolean disconnect_timeout(gpointer user_data) { struct avdtp *session = user_data; struct audio_device *dev; gboolean stream_setup; session->dc_timer = 0; stream_setup = session->stream_setup; session->stream_setup = FALSE; dev = manager_get_device(&session->server->src, &session->dst, FALSE); if (dev && dev->sink && stream_setup) sink_setup_stream(dev->sink, session); else if (dev && dev->source && stream_setup) source_setup_stream(dev->source, session); else connection_lost(session, ETIMEDOUT); return FALSE; } static void remove_disconnect_timer(struct avdtp *session) { g_source_remove(session->dc_timer); session->dc_timer = 0; session->stream_setup = FALSE; } static void set_disconnect_timer(struct avdtp *session) { if (session->dc_timer) remove_disconnect_timer(session); if (session->device_disconnect) { session->dc_timer = g_idle_add(disconnect_timeout, session); return; } session->dc_timer = g_timeout_add_seconds(DISCONNECT_TIMEOUT, disconnect_timeout, session); } void avdtp_error_init(struct avdtp_error *err, uint8_t category, int id) { err->category = category; if (category == AVDTP_ERRNO) err->err.posix_errno = id; else err->err.error_code = id; } uint8_t avdtp_error_category(struct avdtp_error *err) { return err->category; } int avdtp_error_error_code(struct avdtp_error *err) { assert(err->category != AVDTP_ERRNO); return err->err.error_code; } int avdtp_error_posix_errno(struct avdtp_error *err) { assert(err->category == AVDTP_ERRNO); return err->err.posix_errno; } static struct avdtp_stream *find_stream_by_rseid(struct avdtp *session, uint8_t rseid) { GSList *l; for (l = session->streams; l != NULL; l = g_slist_next(l)) { struct avdtp_stream *stream = l->data; if (stream->rseid == rseid) return stream; } return NULL; } static struct avdtp_remote_sep *find_remote_sep(GSList *seps, uint8_t seid) { GSList *l; for (l = seps; l != NULL; l = g_slist_next(l)) { struct avdtp_remote_sep *sep = l->data; if (sep->seid == seid) return sep; } return NULL; } static void avdtp_set_state(struct avdtp *session, avdtp_session_state_t new_state) { GSList *l; struct audio_device *dev; bdaddr_t src, dst; avdtp_session_state_t old_state = session->state; session->state = new_state; avdtp_get_peers(session, &src, &dst); dev = manager_get_device(&src, &dst, FALSE); if (dev == NULL) { error("avdtp_set_state(): no matching audio device"); return; } for (l = avdtp_callbacks; l != NULL; l = l->next) { struct avdtp_state_callback *cb = l->data; cb->cb(dev, session, old_state, new_state, cb->user_data); } } static void stream_free(struct avdtp_stream *stream) { struct avdtp_remote_sep *rsep; stream->lsep->info.inuse = 0; stream->lsep->stream = NULL; rsep = find_remote_sep(stream->session->seps, stream->rseid); if (rsep) rsep->stream = NULL; if (stream->timer) g_source_remove(stream->timer); if (stream->io) close_stream(stream); if (stream->io_id) g_source_remove(stream->io_id); g_slist_free_full(stream->callbacks, g_free); g_slist_free_full(stream->caps, g_free); g_free(stream); } static gboolean stream_timeout(gpointer user_data) { struct avdtp_stream *stream = user_data; struct avdtp *session = stream->session; if (avdtp_close(session, stream, FALSE) < 0) error("stream_timeout: closing AVDTP stream failed"); stream->idle_timer = 0; return FALSE; } static gboolean transport_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct avdtp_stream *stream = data; struct avdtp_local_sep *sep = stream->lsep; if (stream->close_int && sep->cfm && sep->cfm->close) sep->cfm->close(stream->session, sep, stream, NULL, sep->user_data); if (!(cond & G_IO_NVAL)) close_stream(stream); stream->io_id = 0; if (!stream->abort_int) avdtp_sep_set_state(stream->session, sep, AVDTP_STATE_IDLE); return FALSE; } static int get_send_buffer_size(int sk) { int size; socklen_t optlen = sizeof(size); if (getsockopt(sk, SOL_SOCKET, SO_SNDBUF, &size, &optlen) < 0) { int err = -errno; error("getsockopt(SO_SNDBUF) failed: %s (%d)", strerror(-err), -err); return err; } /* * Doubled value is returned by getsockopt since kernel uses that * space for its own purposes (see man 7 socket, bookkeeping overhead * for SO_SNDBUF). */ return size / 2; } static int set_send_buffer_size(int sk, int size) { socklen_t optlen = sizeof(size); if (setsockopt(sk, SOL_SOCKET, SO_SNDBUF, &size, optlen) < 0) { int err = -errno; error("setsockopt(SO_SNDBUF) failed: %s (%d)", strerror(-err), -err); return err; } return 0; } static void handle_transport_connect(struct avdtp *session, GIOChannel *io, uint16_t imtu, uint16_t omtu) { struct avdtp_stream *stream = session->pending_open; struct avdtp_local_sep *sep = stream->lsep; int sk, buf_size, min_buf_size; GError *err = NULL; session->pending_open = NULL; if (stream->timer) { g_source_remove(stream->timer); stream->timer = 0; } if (io == NULL) { if (!stream->open_acp && sep->cfm && sep->cfm->open) { struct avdtp_error err; avdtp_error_init(&err, AVDTP_ERRNO, EIO); sep->cfm->open(session, sep, NULL, &err, sep->user_data); } return; } if (stream->io == NULL) stream->io = g_io_channel_ref(io); stream->omtu = omtu; stream->imtu = imtu; /* Apply special settings only if local SEP is of type SRC */ if (sep->info.type != AVDTP_SEP_TYPE_SOURCE) goto proceed; bt_io_set(stream->io, BT_IO_L2CAP, &err, BT_IO_OPT_FLUSHABLE, TRUE, BT_IO_OPT_INVALID); if (err != NULL) { error("Enabling flushable packets failed: %s", err->message); g_error_free(err); } else DBG("Flushable packets enabled"); sk = g_io_channel_unix_get_fd(stream->io); buf_size = get_send_buffer_size(sk); if (buf_size < 0) goto proceed; DBG("sk %d, omtu %d, send buffer size %d", sk, omtu, buf_size); min_buf_size = omtu * 2; if (buf_size < min_buf_size) { DBG("send buffer size to be increassed to %d", min_buf_size); set_send_buffer_size(sk, min_buf_size); } proceed: if (!stream->open_acp && sep->cfm && sep->cfm->open) sep->cfm->open(session, sep, stream, NULL, sep->user_data); avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN); stream->io_id = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) transport_cb, stream); } static int pending_req_cmp(gconstpointer a, gconstpointer b) { const struct pending_req *req = a; const struct avdtp_stream *stream = b; if (req->stream == stream) return 0; return -1; } static void cleanup_queue(struct avdtp *session, struct avdtp_stream *stream) { GSList *l; struct pending_req *req; while ((l = g_slist_find_custom(session->prio_queue, stream, pending_req_cmp))) { req = l->data; pending_req_free(req); session->prio_queue = g_slist_remove(session->prio_queue, req); } while ((l = g_slist_find_custom(session->req_queue, stream, pending_req_cmp))) { req = l->data; pending_req_free(req); session->req_queue = g_slist_remove(session->req_queue, req); } } static void handle_unanswered_req(struct avdtp *session, struct avdtp_stream *stream) { struct pending_req *req; struct avdtp_local_sep *lsep; struct avdtp_error err; if (session->req->signal_id == AVDTP_ABORT) { /* Avoid freeing the Abort request here */ DBG("handle_unanswered_req: Abort req, returning"); session->req->stream = NULL; return; } req = session->req; session->req = NULL; avdtp_error_init(&err, AVDTP_ERRNO, EIO); lsep = stream->lsep; switch (req->signal_id) { case AVDTP_RECONFIGURE: error("No reply to Reconfigure request"); if (lsep && lsep->cfm && lsep->cfm->reconfigure) lsep->cfm->reconfigure(session, lsep, stream, &err, lsep->user_data); break; case AVDTP_OPEN: error("No reply to Open request"); if (lsep && lsep->cfm && lsep->cfm->open) lsep->cfm->open(session, lsep, stream, &err, lsep->user_data); break; case AVDTP_START: error("No reply to Start request"); if (lsep && lsep->cfm && lsep->cfm->start) lsep->cfm->start(session, lsep, stream, &err, lsep->user_data); break; case AVDTP_SUSPEND: error("No reply to Suspend request"); if (lsep && lsep->cfm && lsep->cfm->suspend) lsep->cfm->suspend(session, lsep, stream, &err, lsep->user_data); break; case AVDTP_CLOSE: error("No reply to Close request"); if (lsep && lsep->cfm && lsep->cfm->close) lsep->cfm->close(session, lsep, stream, &err, lsep->user_data); break; case AVDTP_SET_CONFIGURATION: error("No reply to SetConfiguration request"); if (lsep && lsep->cfm && lsep->cfm->set_configuration) lsep->cfm->set_configuration(session, lsep, stream, &err, lsep->user_data); } pending_req_free(req); } static void avdtp_sep_set_state(struct avdtp *session, struct avdtp_local_sep *sep, avdtp_state_t state) { struct avdtp_stream *stream = sep->stream; avdtp_state_t old_state; struct avdtp_error err, *err_ptr = NULL; GSList *l; if (!stream) { error("Error changing sep state: stream not available"); return; } if (sep->state == state) { avdtp_error_init(&err, AVDTP_ERRNO, EIO); DBG("stream state change failed: %s", avdtp_strerror(&err)); err_ptr = &err; } else { err_ptr = NULL; DBG("stream state changed: %s -> %s", avdtp_statestr(sep->state), avdtp_statestr(state)); } old_state = sep->state; sep->state = state; switch (state) { case AVDTP_STATE_CONFIGURED: if (sep->info.type == AVDTP_SEP_TYPE_SINK) avdtp_delay_report(session, stream, stream->delay); break; case AVDTP_STATE_OPEN: stream->starting = FALSE; if ((old_state > AVDTP_STATE_OPEN && session->auto_dc) || stream->open_acp) stream->idle_timer = g_timeout_add_seconds(STREAM_TIMEOUT, stream_timeout, stream); break; case AVDTP_STATE_STREAMING: if (stream->idle_timer) { g_source_remove(stream->idle_timer); stream->idle_timer = 0; } stream->open_acp = FALSE; break; case AVDTP_STATE_CLOSING: case AVDTP_STATE_ABORTING: if (stream->idle_timer) { g_source_remove(stream->idle_timer); stream->idle_timer = 0; } break; case AVDTP_STATE_IDLE: if (stream->idle_timer) { g_source_remove(stream->idle_timer); stream->idle_timer = 0; } if (session->pending_open == stream) handle_transport_connect(session, NULL, 0, 0); if (session->req && session->req->stream == stream) handle_unanswered_req(session, stream); /* Remove pending commands for this stream from the queue */ cleanup_queue(session, stream); break; default: break; } l = stream->callbacks; while (l != NULL) { struct stream_callback *cb = l->data; l = g_slist_next(l); cb->cb(stream, old_state, state, err_ptr, cb->user_data); } if (state == AVDTP_STATE_IDLE && g_slist_find(session->streams, stream)) { session->streams = g_slist_remove(session->streams, stream); stream_free(stream); } } static void finalize_discovery(struct avdtp *session, int err) { struct avdtp_error avdtp_err; avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err); if (!session->discov_cb) return; session->discov_cb(session, session->seps, err ? &avdtp_err : NULL, session->user_data); session->discov_cb = NULL; session->user_data = NULL; } static void release_stream(struct avdtp_stream *stream, struct avdtp *session) { struct avdtp_local_sep *sep = stream->lsep; if (sep->cfm && sep->cfm->abort && (sep->state != AVDTP_STATE_ABORTING || stream->abort_int)) sep->cfm->abort(session, sep, stream, NULL, sep->user_data); avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE); } static int avdtp_cancel_authorization(struct avdtp *session) { struct audio_device *dev; if (session->state != AVDTP_SESSION_STATE_CONNECTING) return 0; dev = manager_get_device(&session->server->src, &session->dst, FALSE); if (dev == NULL) return -ENODEV; return audio_device_cancel_authorization(dev, auth_cb, session); } static void connection_lost(struct avdtp *session, int err) { char address[18]; ba2str(&session->dst, address); DBG("Disconnected from %s", address); if (err != EACCES) avdtp_cancel_authorization(session); session->free_lock = 1; finalize_discovery(session, err); g_slist_foreach(session->streams, (GFunc) release_stream, session); session->streams = NULL; session->free_lock = 0; if (session->io) { g_io_channel_shutdown(session->io, FALSE, NULL); g_io_channel_unref(session->io); session->io = NULL; } avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED); if (session->io_id) { g_source_remove(session->io_id); session->io_id = 0; } if (session->dc_timer) remove_disconnect_timer(session); session->auto_dc = TRUE; if (session->ref != 1) error("connection_lost: ref count not 1 after all callbacks"); else avdtp_unref(session); } void avdtp_unref(struct avdtp *session) { struct avdtp_server *server; if (!session) return; session->ref--; DBG("%p: ref=%d", session, session->ref); if (session->ref == 1) { if (session->state == AVDTP_SESSION_STATE_CONNECTING && session->io) { avdtp_cancel_authorization(session); g_io_channel_shutdown(session->io, TRUE, NULL); g_io_channel_unref(session->io); session->io = NULL; avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED); } if (session->io) set_disconnect_timer(session); else if (!session->free_lock) /* Drop the local ref if we aren't connected */ session->ref--; } if (session->ref > 0) return; server = session->server; DBG("%p: freeing session and removing from list", session); if (session->dc_timer) remove_disconnect_timer(session); server->sessions = g_slist_remove(server->sessions, session); if (session->req) pending_req_free(session->req); g_slist_free_full(session->seps, g_free); g_free(session->buf); g_free(session); } struct avdtp *avdtp_ref(struct avdtp *session) { session->ref++; DBG("%p: ref=%d", session, session->ref); if (session->dc_timer) remove_disconnect_timer(session); return session; } static struct avdtp_local_sep *find_local_sep_by_seid(struct avdtp_server *server, uint8_t seid) { GSList *l; for (l = server->seps; l != NULL; l = g_slist_next(l)) { struct avdtp_local_sep *sep = l->data; if (sep->info.seid == seid) return sep; } return NULL; } struct avdtp_remote_sep *avdtp_find_remote_sep(struct avdtp *session, struct avdtp_local_sep *lsep) { GSList *l; if (lsep->info.inuse) return NULL; for (l = session->seps; l != NULL; l = g_slist_next(l)) { struct avdtp_remote_sep *sep = l->data; struct avdtp_service_capability *cap; struct avdtp_media_codec_capability *codec_data; /* Type must be different: source <-> sink */ if (sep->type == lsep->info.type) continue; if (sep->media_type != lsep->info.media_type) continue; if (!sep->codec) continue; cap = sep->codec; codec_data = (void *) cap->data; if (codec_data->media_codec_type != lsep->codec) continue; if (sep->stream == NULL) return sep; } return NULL; } static GSList *caps_to_list(uint8_t *data, int size, struct avdtp_service_capability **codec, gboolean *delay_reporting) { GSList *caps; int processed; if (delay_reporting) *delay_reporting = FALSE; for (processed = 0, caps = NULL; processed + 2 <= size;) { struct avdtp_service_capability *cap; uint8_t length, category; category = data[0]; length = data[1]; if (processed + 2 + length > size) { error("Invalid capability data in getcap resp"); break; } cap = g_malloc(sizeof(struct avdtp_service_capability) + length); memcpy(cap, data, 2 + length); processed += 2 + length; data += 2 + length; caps = g_slist_append(caps, cap); if (category == AVDTP_MEDIA_CODEC && length >= sizeof(struct avdtp_media_codec_capability)) *codec = cap; else if (category == AVDTP_DELAY_REPORTING && delay_reporting) *delay_reporting = TRUE; } return caps; } static gboolean avdtp_unknown_cmd(struct avdtp *session, uint8_t transaction, uint8_t signal_id) { return avdtp_send(session, transaction, AVDTP_MSG_TYPE_GEN_REJECT, signal_id, NULL, 0); } static gboolean avdtp_discover_cmd(struct avdtp *session, uint8_t transaction, void *buf, int size) { GSList *l; unsigned int rsp_size, sep_count, i; struct seid_info *seps; gboolean ret; sep_count = g_slist_length(session->server->seps); if (sep_count == 0) { uint8_t err = AVDTP_NOT_SUPPORTED_COMMAND; return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_DISCOVER, &err, sizeof(err)); } rsp_size = sep_count * sizeof(struct seid_info); seps = g_new0(struct seid_info, sep_count); for (l = session->server->seps, i = 0; l != NULL; l = l->next, i++) { struct avdtp_local_sep *sep = l->data; memcpy(&seps[i], &sep->info, sizeof(struct seid_info)); } ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_DISCOVER, seps, rsp_size); g_free(seps); return ret; } static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction, struct seid_req *req, unsigned int size, gboolean get_all) { GSList *l, *caps; struct avdtp_local_sep *sep = NULL; unsigned int rsp_size; uint8_t err, buf[1024], *ptr = buf; uint8_t cmd; cmd = get_all ? AVDTP_GET_ALL_CAPABILITIES : AVDTP_GET_CAPABILITIES; if (size < sizeof(struct seid_req)) { err = AVDTP_BAD_LENGTH; goto failed; } sep = find_local_sep_by_seid(session->server, req->acp_seid); if (!sep) { err = AVDTP_BAD_ACP_SEID; goto failed; } if (get_all && session->server->version < 0x0103) return avdtp_unknown_cmd(session, transaction, cmd); if (!sep->ind->get_capability(session, sep, get_all, &caps, &err, sep->user_data)) goto failed; for (l = caps, rsp_size = 0; l != NULL; l = g_slist_next(l)) { struct avdtp_service_capability *cap = l->data; if (rsp_size + cap->length + 2 > sizeof(buf)) break; memcpy(ptr, cap, cap->length + 2); rsp_size += cap->length + 2; ptr += cap->length + 2; g_free(cap); } g_slist_free(caps); return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, cmd, buf, rsp_size); failed: return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, cmd, &err, sizeof(err)); } static void setconf_cb(struct avdtp *session, struct avdtp_stream *stream, struct avdtp_error *err) { struct conf_rej rej; struct avdtp_local_sep *sep; if (err != NULL) { rej.error = AVDTP_UNSUPPORTED_CONFIGURATION; rej.category = err->err.error_code; avdtp_send(session, session->in.transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, &rej, sizeof(rej)); return; } if (!avdtp_send(session, session->in.transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_SET_CONFIGURATION, NULL, 0)) { stream_free(stream); return; } sep = stream->lsep; sep->stream = stream; sep->info.inuse = 1; session->streams = g_slist_append(session->streams, stream); avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED); } static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction, struct setconf_req *req, unsigned int size) { struct conf_rej rej; struct avdtp_local_sep *sep; struct avdtp_stream *stream; uint8_t err, category = 0x00; struct audio_device *dev; bdaddr_t src, dst; GSList *l; if (size < sizeof(struct setconf_req)) { error("Too short getcap request"); return FALSE; } sep = find_local_sep_by_seid(session->server, req->acp_seid); if (!sep) { err = AVDTP_BAD_ACP_SEID; goto failed; } if (sep->stream) { err = AVDTP_SEP_IN_USE; goto failed; } avdtp_get_peers(session, &src, &dst); dev = manager_get_device(&src, &dst, FALSE); if (!dev) { error("Unable to get a audio device object"); err = AVDTP_BAD_STATE; goto failed; } switch (sep->info.type) { case AVDTP_SEP_TYPE_SOURCE: if (!dev->sink) { btd_device_add_uuid(dev->btd_dev, A2DP_SINK_UUID); if (!dev->sink) { error("Unable to get a audio sink object"); err = AVDTP_BAD_STATE; goto failed; } } break; case AVDTP_SEP_TYPE_SINK: if (!dev->source) { btd_device_add_uuid(dev->btd_dev, A2DP_SOURCE_UUID); if (!dev->source) { error("Unable to get a audio source object"); err = AVDTP_BAD_STATE; goto failed; } } break; } stream = g_new0(struct avdtp_stream, 1); stream->session = session; stream->lsep = sep; stream->rseid = req->int_seid; stream->caps = caps_to_list(req->caps, size - sizeof(struct setconf_req), &stream->codec, &stream->delay_reporting); /* Verify that the Media Transport capability's length = 0. Reject otherwise */ for (l = stream->caps; l != NULL; l = g_slist_next(l)) { struct avdtp_service_capability *cap = l->data; if (cap->category == AVDTP_MEDIA_TRANSPORT && cap->length != 0) { err = AVDTP_BAD_MEDIA_TRANSPORT_FORMAT; goto failed_stream; } } if (stream->delay_reporting && session->version < 0x0103) session->version = 0x0103; if (sep->ind && sep->ind->set_configuration) { if (!sep->ind->set_configuration(session, sep, stream, stream->caps, setconf_cb, sep->user_data)) { err = AVDTP_UNSUPPORTED_CONFIGURATION; category = 0x00; goto failed_stream; } } else { if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_SET_CONFIGURATION, NULL, 0)) { stream_free(stream); return FALSE; } sep->stream = stream; sep->info.inuse = 1; session->streams = g_slist_append(session->streams, stream); avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED); } return TRUE; failed_stream: stream_free(stream); failed: rej.error = err; rej.category = category; return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_SET_CONFIGURATION, &rej, sizeof(rej)); } static gboolean avdtp_getconf_cmd(struct avdtp *session, uint8_t transaction, struct seid_req *req, int size) { GSList *l; struct avdtp_local_sep *sep = NULL; int rsp_size; uint8_t err; uint8_t buf[1024]; uint8_t *ptr = buf; if (size < (int) sizeof(struct seid_req)) { error("Too short getconf request"); return FALSE; } memset(buf, 0, sizeof(buf)); sep = find_local_sep_by_seid(session->server, req->acp_seid); if (!sep) { err = AVDTP_BAD_ACP_SEID; goto failed; } if (!sep->stream || !sep->stream->caps) { err = AVDTP_UNSUPPORTED_CONFIGURATION; goto failed; } for (l = sep->stream->caps, rsp_size = 0; l != NULL; l = g_slist_next(l)) { struct avdtp_service_capability *cap = l->data; if (rsp_size + cap->length + 2 > (int) sizeof(buf)) break; memcpy(ptr, cap, cap->length + 2); rsp_size += cap->length + 2; ptr += cap->length + 2; } return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_GET_CONFIGURATION, buf, rsp_size); failed: return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_GET_CONFIGURATION, &err, sizeof(err)); } static gboolean avdtp_reconf_cmd(struct avdtp *session, uint8_t transaction, struct seid_req *req, int size) { struct conf_rej rej; rej.error = AVDTP_NOT_SUPPORTED_COMMAND; rej.category = 0x00; return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_RECONFIGURE, &rej, sizeof(rej)); } static void check_seid_collision(struct pending_req *req, uint8_t id) { struct seid_req *seid = req->data; if (seid->acp_seid == id) req->collided = TRUE; } static void check_start_collision(struct pending_req *req, uint8_t id) { struct start_req *start = req->data; struct seid *seid = &start->first_seid; int count = 1 + req->data_size - sizeof(struct start_req); int i; for (i = 0; i < count; i++, seid++) { if (seid->seid == id) { req->collided = TRUE; return; } } } static void check_suspend_collision(struct pending_req *req, uint8_t id) { struct suspend_req *suspend = req->data; struct seid *seid = &suspend->first_seid; int count = 1 + req->data_size - sizeof(struct suspend_req); int i; for (i = 0; i < count; i++, seid++) { if (seid->seid == id) { req->collided = TRUE; return; } } } static void avdtp_check_collision(struct avdtp *session, uint8_t cmd, struct avdtp_stream *stream) { struct pending_req *req = session->req; if (req == NULL || (req->signal_id != cmd && cmd != AVDTP_ABORT)) return; if (cmd == AVDTP_ABORT) cmd = req->signal_id; switch (cmd) { case AVDTP_OPEN: case AVDTP_CLOSE: check_seid_collision(req, stream->rseid); break; case AVDTP_START: check_start_collision(req, stream->rseid); break; case AVDTP_SUSPEND: check_suspend_collision(req, stream->rseid); break; } } static gboolean avdtp_open_cmd(struct avdtp *session, uint8_t transaction, struct seid_req *req, unsigned int size) { struct avdtp_local_sep *sep; struct avdtp_stream *stream; uint8_t err; if (size < sizeof(struct seid_req)) { error("Too short abort request"); return FALSE; } sep = find_local_sep_by_seid(session->server, req->acp_seid); if (!sep) { err = AVDTP_BAD_ACP_SEID; goto failed; } if (sep->state != AVDTP_STATE_CONFIGURED) { err = AVDTP_BAD_STATE; goto failed; } stream = sep->stream; if (sep->ind && sep->ind->open) { if (!sep->ind->open(session, sep, stream, &err, sep->user_data)) goto failed; } avdtp_check_collision(session, AVDTP_OPEN, stream); if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_OPEN, NULL, 0)) return FALSE; stream->open_acp = TRUE; session->pending_open = stream; stream->timer = g_timeout_add_seconds(REQ_TIMEOUT, stream_open_timeout, stream); return TRUE; failed: return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_OPEN, &err, sizeof(err)); } static gboolean avdtp_start_cmd(struct avdtp *session, uint8_t transaction, struct start_req *req, unsigned int size) { struct avdtp_local_sep *sep; struct avdtp_stream *stream; struct stream_rej rej; struct seid *seid; uint8_t err, failed_seid; int seid_count, i; if (size < sizeof(struct start_req)) { error("Too short start request"); return FALSE; } seid_count = 1 + size - sizeof(struct start_req); seid = &req->first_seid; for (i = 0; i < seid_count; i++, seid++) { failed_seid = seid->seid; sep = find_local_sep_by_seid(session->server, req->first_seid.seid); if (!sep || !sep->stream) { err = AVDTP_BAD_ACP_SEID; goto failed; } stream = sep->stream; /* Also reject start cmd if state is not open */ if (sep->state != AVDTP_STATE_OPEN) { err = AVDTP_BAD_STATE; goto failed; } stream->starting = TRUE; if (sep->ind && sep->ind->start) { if (!sep->ind->start(session, sep, stream, &err, sep->user_data)) goto failed; } avdtp_check_collision(session, AVDTP_START, stream); avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING); } return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_START, NULL, 0); failed: DBG("Rejecting (%d)", err); memset(&rej, 0, sizeof(rej)); rej.acp_seid = failed_seid; rej.error = err; return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_START, &rej, sizeof(rej)); } static gboolean avdtp_close_cmd(struct avdtp *session, uint8_t transaction, struct seid_req *req, unsigned int size) { struct avdtp_local_sep *sep; struct avdtp_stream *stream; uint8_t err; if (size < sizeof(struct seid_req)) { error("Too short close request"); return FALSE; } sep = find_local_sep_by_seid(session->server, req->acp_seid); if (!sep || !sep->stream) { err = AVDTP_BAD_ACP_SEID; goto failed; } if (sep->state != AVDTP_STATE_OPEN && sep->state != AVDTP_STATE_STREAMING) { err = AVDTP_BAD_STATE; goto failed; } stream = sep->stream; if (sep->ind && sep->ind->close) { if (!sep->ind->close(session, sep, stream, &err, sep->user_data)) goto failed; } avdtp_check_collision(session, AVDTP_CLOSE, stream); avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING); if (!avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_CLOSE, NULL, 0)) return FALSE; stream->timer = g_timeout_add_seconds(REQ_TIMEOUT, stream_close_timeout, stream); return TRUE; failed: return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_CLOSE, &err, sizeof(err)); } static gboolean avdtp_suspend_cmd(struct avdtp *session, uint8_t transaction, struct suspend_req *req, unsigned int size) { struct avdtp_local_sep *sep; struct avdtp_stream *stream; struct stream_rej rej; struct seid *seid; uint8_t err, failed_seid; int seid_count, i; if (size < sizeof(struct suspend_req)) { error("Too short suspend request"); return FALSE; } seid_count = 1 + size - sizeof(struct suspend_req); seid = &req->first_seid; for (i = 0; i < seid_count; i++, seid++) { failed_seid = seid->seid; sep = find_local_sep_by_seid(session->server, req->first_seid.seid); if (!sep || !sep->stream) { err = AVDTP_BAD_ACP_SEID; goto failed; } stream = sep->stream; if (sep->state != AVDTP_STATE_STREAMING) { err = AVDTP_BAD_STATE; goto failed; } if (sep->ind && sep->ind->suspend) { if (!sep->ind->suspend(session, sep, stream, &err, sep->user_data)) goto failed; } avdtp_check_collision(session, AVDTP_SUSPEND, stream); avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN); } return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_SUSPEND, NULL, 0); failed: memset(&rej, 0, sizeof(rej)); rej.acp_seid = failed_seid; rej.error = err; return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_SUSPEND, &rej, sizeof(rej)); } static gboolean avdtp_abort_cmd(struct avdtp *session, uint8_t transaction, struct seid_req *req, unsigned int size) { struct avdtp_local_sep *sep; uint8_t err; gboolean ret; if (size < sizeof(struct seid_req)) { error("Too short abort request"); return FALSE; } sep = find_local_sep_by_seid(session->server, req->acp_seid); if (!sep || !sep->stream) return TRUE; if (sep->ind && sep->ind->abort) sep->ind->abort(session, sep, sep->stream, &err, sep->user_data); avdtp_check_collision(session, AVDTP_ABORT, sep->stream); ret = avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_ABORT, NULL, 0); if (ret) avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING); return ret; } static gboolean avdtp_secctl_cmd(struct avdtp *session, uint8_t transaction, struct seid_req *req, int size) { return avdtp_unknown_cmd(session, transaction, AVDTP_SECURITY_CONTROL); } static gboolean avdtp_delayreport_cmd(struct avdtp *session, uint8_t transaction, struct delay_req *req, unsigned int size) { struct avdtp_local_sep *sep; struct avdtp_stream *stream; uint8_t err; if (size < sizeof(struct delay_req)) { error("Too short delay report request"); return FALSE; } sep = find_local_sep_by_seid(session->server, req->acp_seid); if (!sep || !sep->stream) { err = AVDTP_BAD_ACP_SEID; goto failed; } stream = sep->stream; if (sep->state != AVDTP_STATE_CONFIGURED && sep->state != AVDTP_STATE_STREAMING) { err = AVDTP_BAD_STATE; goto failed; } stream->delay = ntohs(req->delay); if (sep->ind && sep->ind->delayreport) { if (!sep->ind->delayreport(session, sep, stream->rseid, stream->delay, &err, sep->user_data)) goto failed; } return avdtp_send(session, transaction, AVDTP_MSG_TYPE_ACCEPT, AVDTP_DELAY_REPORT, NULL, 0); failed: return avdtp_send(session, transaction, AVDTP_MSG_TYPE_REJECT, AVDTP_DELAY_REPORT, &err, sizeof(err)); } static gboolean avdtp_parse_cmd(struct avdtp *session, uint8_t transaction, uint8_t signal_id, void *buf, int size) { switch (signal_id) { case AVDTP_DISCOVER: DBG("Received DISCOVER_CMD"); return avdtp_discover_cmd(session, transaction, buf, size); case AVDTP_GET_CAPABILITIES: DBG("Received GET_CAPABILITIES_CMD"); return avdtp_getcap_cmd(session, transaction, buf, size, FALSE); case AVDTP_GET_ALL_CAPABILITIES: DBG("Received GET_ALL_CAPABILITIES_CMD"); return avdtp_getcap_cmd(session, transaction, buf, size, TRUE); case AVDTP_SET_CONFIGURATION: DBG("Received SET_CONFIGURATION_CMD"); return avdtp_setconf_cmd(session, transaction, buf, size); case AVDTP_GET_CONFIGURATION: DBG("Received GET_CONFIGURATION_CMD"); return avdtp_getconf_cmd(session, transaction, buf, size); case AVDTP_RECONFIGURE: DBG("Received RECONFIGURE_CMD"); return avdtp_reconf_cmd(session, transaction, buf, size); case AVDTP_OPEN: DBG("Received OPEN_CMD"); return avdtp_open_cmd(session, transaction, buf, size); case AVDTP_START: DBG("Received START_CMD"); return avdtp_start_cmd(session, transaction, buf, size); case AVDTP_CLOSE: DBG("Received CLOSE_CMD"); return avdtp_close_cmd(session, transaction, buf, size); case AVDTP_SUSPEND: DBG("Received SUSPEND_CMD"); return avdtp_suspend_cmd(session, transaction, buf, size); case AVDTP_ABORT: DBG("Received ABORT_CMD"); return avdtp_abort_cmd(session, transaction, buf, size); case AVDTP_SECURITY_CONTROL: DBG("Received SECURITY_CONTROL_CMD"); return avdtp_secctl_cmd(session, transaction, buf, size); case AVDTP_DELAY_REPORT: DBG("Received DELAY_REPORT_CMD"); return avdtp_delayreport_cmd(session, transaction, buf, size); default: DBG("Received unknown request id %u", signal_id); return avdtp_unknown_cmd(session, transaction, signal_id); } } enum avdtp_parse_result { PARSE_ERROR, PARSE_FRAGMENT, PARSE_SUCCESS }; static enum avdtp_parse_result avdtp_parse_data(struct avdtp *session, void *buf, size_t size) { struct avdtp_common_header *header = buf; struct avdtp_single_header *single = (void *) session->buf; struct avdtp_start_header *start = (void *) session->buf; void *payload; gsize payload_size; switch (header->packet_type) { case AVDTP_PKT_TYPE_SINGLE: if (size < sizeof(*single)) { error("Received too small single packet (%zu bytes)", size); return PARSE_ERROR; } if (session->in.active) { error("SINGLE: Invalid AVDTP packet fragmentation"); return PARSE_ERROR; } payload = session->buf + sizeof(*single); payload_size = size - sizeof(*single); session->in.active = TRUE; session->in.data_size = 0; session->in.no_of_packets = 1; session->in.transaction = header->transaction; session->in.message_type = header->message_type; session->in.signal_id = single->signal_id; break; case AVDTP_PKT_TYPE_START: if (size < sizeof(*start)) { error("Received too small start packet (%zu bytes)", size); return PARSE_ERROR; } if (session->in.active) { error("START: Invalid AVDTP packet fragmentation"); return PARSE_ERROR; } session->in.active = TRUE; session->in.data_size = 0; session->in.transaction = header->transaction; session->in.message_type = header->message_type; session->in.no_of_packets = start->no_of_packets; session->in.signal_id = start->signal_id; payload = session->buf + sizeof(*start); payload_size = size - sizeof(*start); break; case AVDTP_PKT_TYPE_CONTINUE: if (size < sizeof(struct avdtp_continue_header)) { error("Received too small continue packet (%zu bytes)", size); return PARSE_ERROR; } if (!session->in.active) { error("CONTINUE: Invalid AVDTP packet fragmentation"); return PARSE_ERROR; } if (session->in.transaction != header->transaction) { error("Continue transaction id doesn't match"); return PARSE_ERROR; } if (session->in.no_of_packets <= 1) { error("Too few continue packets"); return PARSE_ERROR; } payload = session->buf + sizeof(struct avdtp_continue_header); payload_size = size - sizeof(struct avdtp_continue_header); break; case AVDTP_PKT_TYPE_END: if (size < sizeof(struct avdtp_continue_header)) { error("Received too small end packet (%zu bytes)", size); return PARSE_ERROR; } if (!session->in.active) { error("END: Invalid AVDTP packet fragmentation"); return PARSE_ERROR; } if (session->in.transaction != header->transaction) { error("End transaction id doesn't match"); return PARSE_ERROR; } if (session->in.no_of_packets > 1) { error("Got an end packet too early"); return PARSE_ERROR; } payload = session->buf + sizeof(struct avdtp_continue_header); payload_size = size - sizeof(struct avdtp_continue_header); break; default: error("Invalid AVDTP packet type 0x%02X", header->packet_type); return PARSE_ERROR; } if (session->in.data_size + payload_size > sizeof(session->in.buf)) { error("Not enough incoming buffer space!"); return PARSE_ERROR; } memcpy(session->in.buf + session->in.data_size, payload, payload_size); session->in.data_size += payload_size; if (session->in.no_of_packets > 1) { session->in.no_of_packets--; DBG("Received AVDTP fragment. %d to go", session->in.no_of_packets); return PARSE_FRAGMENT; } session->in.active = FALSE; return PARSE_SUCCESS; } static gboolean session_cb(GIOChannel *chan, GIOCondition cond, gpointer data) { struct avdtp *session = data; struct avdtp_common_header *header; ssize_t size; int fd; DBG(""); if (cond & G_IO_NVAL) return FALSE; header = (void *) session->buf; if (cond & (G_IO_HUP | G_IO_ERR)) goto failed; fd = g_io_channel_unix_get_fd(chan); size = read(fd, session->buf, session->imtu); if (size < 0) { error("IO Channel read error"); goto failed; } if ((size_t) size < sizeof(struct avdtp_common_header)) { error("Received too small packet (%zu bytes)", size); goto failed; } switch (avdtp_parse_data(session, session->buf, size)) { case PARSE_ERROR: goto failed; case PARSE_FRAGMENT: return TRUE; case PARSE_SUCCESS: break; } if (session->in.message_type == AVDTP_MSG_TYPE_COMMAND) { if (!avdtp_parse_cmd(session, session->in.transaction, session->in.signal_id, session->in.buf, session->in.data_size)) { error("Unable to handle command. Disconnecting"); goto failed; } if (session->ref == 1 && !session->streams && !session->req) set_disconnect_timer(session); if (session->streams && session->dc_timer) remove_disconnect_timer(session); if (session->req && session->req->collided) { DBG("Collision detected"); goto next; } return TRUE; } if (session->req == NULL) { error("No pending request, ignoring message"); return TRUE; } if (header->transaction != session->req->transaction) { error("Transaction label doesn't match"); return TRUE; } if (session->in.signal_id != session->req->signal_id) { error("Response signal doesn't match"); return TRUE; } g_source_remove(session->req->timeout); session->req->timeout = 0; switch (header->message_type) { case AVDTP_MSG_TYPE_ACCEPT: if (!avdtp_parse_resp(session, session->req->stream, session->in.transaction, session->in.signal_id, session->in.buf, session->in.data_size)) { error("Unable to parse accept response"); goto failed; } break; case AVDTP_MSG_TYPE_REJECT: if (!avdtp_parse_rej(session, session->req->stream, session->in.transaction, session->in.signal_id, session->in.buf, session->in.data_size)) { error("Unable to parse reject response"); goto failed; } break; case AVDTP_MSG_TYPE_GEN_REJECT: error("Received a General Reject message"); break; default: error("Unknown message type 0x%02X", header->message_type); break; } next: pending_req_free(session->req); session->req = NULL; process_queue(session); return TRUE; failed: connection_lost(session, EIO); return FALSE; } static struct avdtp *find_session(GSList *list, const bdaddr_t *dst) { for (; list != NULL; list = g_slist_next(list)) { struct avdtp *s = list->data; if (bacmp(dst, &s->dst)) continue; return s; } return NULL; } static uint16_t get_version(struct avdtp *session) { struct btd_adapter *adapter; struct btd_device *device; const sdp_record_t *rec; sdp_list_t *protos; sdp_data_t *proto_desc; char addr[18]; uint16_t ver = 0x0100; adapter = manager_find_adapter(&session->server->src); if (!adapter) return ver; ba2str(&session->dst, addr); device = adapter_find_device(adapter, addr); if (!device) return ver; rec = btd_device_get_record(device, A2DP_SINK_UUID); if (!rec) rec = btd_device_get_record(device, A2DP_SOURCE_UUID); if (!rec) return ver; if (sdp_get_access_protos(rec, &protos) < 0) return ver; proto_desc = sdp_get_proto_desc(protos, AVDTP_UUID); if (proto_desc && proto_desc->dtd == SDP_UINT16) ver = proto_desc->val.uint16; sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); return ver; } static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst) { struct avdtp_server *server; struct avdtp *session; assert(src != NULL); assert(dst != NULL); server = find_server(servers, src); if (server == NULL) return NULL; session = find_session(server->sessions, dst); if (session) { if (session->pending_auth) return NULL; else return session; } session = g_new0(struct avdtp, 1); session->server = server; bacpy(&session->dst, dst); session->ref = 1; /* We don't use avdtp_set_state() here since this isn't a state change * but just setting of the initial state */ session->state = AVDTP_SESSION_STATE_DISCONNECTED; session->auto_dc = TRUE; session->version = get_version(session); server->sessions = g_slist_append(server->sessions, session); return session; } struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst) { struct avdtp *session; session = avdtp_get_internal(src, dst); if (!session) return NULL; return avdtp_ref(session); } static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct avdtp *session = user_data; char address[18]; GError *gerr = NULL; if (err) { error("%s", err->message); goto failed; } if (!session->io) session->io = g_io_channel_ref(chan); bt_io_get(chan, BT_IO_L2CAP, &gerr, BT_IO_OPT_OMTU, &session->omtu, BT_IO_OPT_IMTU, &session->imtu, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); goto failed; } ba2str(&session->dst, address); DBG("AVDTP: connected %s channel to %s", session->pending_open ? "transport" : "signaling", address); if (session->state == AVDTP_SESSION_STATE_CONNECTING) { DBG("AVDTP imtu=%u, omtu=%u", session->imtu, session->omtu); session->buf = g_malloc0(MAX(session->imtu, session->omtu)); avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTED); if (session->io_id) g_source_remove(session->io_id); /* This watch should be low priority since otherwise the * connect callback might be dispatched before the session * callback if the kernel wakes us up at the same time for * them. This could happen if a headset is very quick in * sending the Start command after connecting the stream * transport channel. */ session->io_id = g_io_add_watch_full(chan, G_PRIORITY_LOW, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) session_cb, session, NULL); if (session->stream_setup) { set_disconnect_timer(session); avdtp_set_auto_disconnect(session, FALSE); } } else if (session->pending_open) handle_transport_connect(session, chan, session->imtu, session->omtu); else goto failed; process_queue(session); return; failed: if (session->pending_open) { struct avdtp_stream *stream = session->pending_open; handle_transport_connect(session, NULL, 0, 0); if (avdtp_abort(session, stream) < 0) avdtp_sep_set_state(session, stream->lsep, AVDTP_STATE_IDLE); } else connection_lost(session, EIO); } static void auth_cb(DBusError *derr, void *user_data) { struct avdtp *session = user_data; GError *err = NULL; if (derr && dbus_error_is_set(derr)) { error("Access denied: %s", derr->message); connection_lost(session, EACCES); return; } if (!bt_io_accept(session->io, avdtp_connect_cb, session, NULL, &err)) { error("bt_io_accept: %s", err->message); connection_lost(session, EACCES); g_error_free(err); return; } /* This is so that avdtp_connect_cb will know to do the right thing * with respect to the disconnect timer */ session->stream_setup = TRUE; } static void avdtp_confirm_cb(GIOChannel *chan, gpointer data) { struct avdtp *session; struct audio_device *dev; char address[18]; bdaddr_t src, dst; int perr; GError *err = NULL; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } DBG("AVDTP: incoming connect from %s", address); session = avdtp_get_internal(&src, &dst); if (!session) goto drop; /* This state (ie, session is already *connecting*) happens when the * device initiates a connect (really a config'd L2CAP channel) even * though there is a connect we initiated in progress. In sink.c & * source.c, this state is referred to as XCASE connect:connect. * Abort the device's channel in favor of our own. */ if (session->state == AVDTP_SESSION_STATE_CONNECTING) { DBG("connect already in progress (XCASE connect:connect)"); goto drop; } if (session->pending_open && session->pending_open->open_acp) { if (!bt_io_accept(chan, avdtp_connect_cb, session, NULL, NULL)) goto drop; return; } if (session->io) { error("Refusing unexpected connect from %s", address); goto drop; } dev = manager_get_device(&src, &dst, FALSE); if (!dev) { dev = manager_get_device(&src, &dst, TRUE); if (!dev) { error("Unable to get audio device object for %s", address); goto drop; } btd_device_add_uuid(dev->btd_dev, ADVANCED_AUDIO_UUID); } session->io = g_io_channel_ref(chan); avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTING); session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) session_cb, session); perr = audio_device_request_authorization(dev, ADVANCED_AUDIO_UUID, auth_cb, session); if (perr < 0) { avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED); avdtp_unref(session); goto drop; } dev->auto_connect = auto_connect; return; drop: g_io_channel_shutdown(chan, TRUE, NULL); } static GIOChannel *l2cap_connect(struct avdtp *session) { GError *err = NULL; GIOChannel *io; io = bt_io_connect(BT_IO_L2CAP, avdtp_connect_cb, session, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &session->server->src, BT_IO_OPT_DEST_BDADDR, &session->dst, BT_IO_OPT_PSM, AVDTP_PSM, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID); if (!io) { error("%s", err->message); g_error_free(err); return NULL; } return io; } static void queue_request(struct avdtp *session, struct pending_req *req, gboolean priority) { if (priority) session->prio_queue = g_slist_append(session->prio_queue, req); else session->req_queue = g_slist_append(session->req_queue, req); } static uint8_t req_get_seid(struct pending_req *req) { if (req->signal_id == AVDTP_DISCOVER) return 0; return ((struct seid_req *) (req->data))->acp_seid; } static int cancel_request(struct avdtp *session, int err) { struct pending_req *req; struct seid_req sreq; struct avdtp_local_sep *lsep; struct avdtp_stream *stream; uint8_t seid; struct avdtp_error averr; req = session->req; session->req = NULL; avdtp_error_init(&averr, AVDTP_ERRNO, err); seid = req_get_seid(req); if (seid) stream = find_stream_by_rseid(session, seid); else stream = NULL; if (stream) { stream->abort_int = TRUE; lsep = stream->lsep; } else lsep = NULL; switch (req->signal_id) { case AVDTP_RECONFIGURE: error("Reconfigure: %s (%d)", strerror(err), err); if (lsep && lsep->cfm && lsep->cfm->reconfigure) lsep->cfm->reconfigure(session, lsep, stream, &averr, lsep->user_data); break; case AVDTP_OPEN: error("Open: %s (%d)", strerror(err), err); if (lsep && lsep->cfm && lsep->cfm->open) lsep->cfm->open(session, lsep, stream, &averr, lsep->user_data); break; case AVDTP_START: error("Start: %s (%d)", strerror(err), err); if (lsep && lsep->cfm && lsep->cfm->start) { lsep->cfm->start(session, lsep, stream, &averr, lsep->user_data); if (stream) stream->starting = FALSE; } break; case AVDTP_SUSPEND: error("Suspend: %s (%d)", strerror(err), err); if (lsep && lsep->cfm && lsep->cfm->suspend) lsep->cfm->suspend(session, lsep, stream, &averr, lsep->user_data); break; case AVDTP_CLOSE: error("Close: %s (%d)", strerror(err), err); if (lsep && lsep->cfm && lsep->cfm->close) { lsep->cfm->close(session, lsep, stream, &averr, lsep->user_data); if (stream) stream->close_int = FALSE; } break; case AVDTP_SET_CONFIGURATION: error("SetConfiguration: %s (%d)", strerror(err), err); if (lsep && lsep->cfm && lsep->cfm->set_configuration) lsep->cfm->set_configuration(session, lsep, stream, &averr, lsep->user_data); goto failed; case AVDTP_DISCOVER: error("Discover: %s (%d)", strerror(err), err); goto failed; case AVDTP_GET_CAPABILITIES: error("GetCapabilities: %s (%d)", strerror(err), err); goto failed; case AVDTP_ABORT: error("Abort: %s (%d)", strerror(err), err); goto failed; } if (!stream) goto failed; memset(&sreq, 0, sizeof(sreq)); sreq.acp_seid = seid; err = send_request(session, TRUE, stream, AVDTP_ABORT, &sreq, sizeof(sreq)); if (err < 0) { error("Unable to send abort request"); goto failed; } goto done; failed: connection_lost(session, err); done: pending_req_free(req); return err; } static gboolean request_timeout(gpointer user_data) { struct avdtp *session = user_data; cancel_request(session, ETIMEDOUT); return FALSE; } static int send_req(struct avdtp *session, gboolean priority, struct pending_req *req) { static int transaction = 0; int err; if (session->state == AVDTP_SESSION_STATE_DISCONNECTED) { session->io = l2cap_connect(session); if (!session->io) { err = -EIO; goto failed; } avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTING); } if (session->state < AVDTP_SESSION_STATE_CONNECTED || session->req != NULL) { queue_request(session, req, priority); return 0; } req->transaction = transaction++; transaction %= 16; /* FIXME: Should we retry to send if the buffer was not totally sent or in case of EINTR? */ if (!avdtp_send(session, req->transaction, AVDTP_MSG_TYPE_COMMAND, req->signal_id, req->data, req->data_size)) { err = -EIO; goto failed; } session->req = req; req->timeout = g_timeout_add_seconds(req->signal_id == AVDTP_ABORT ? ABORT_TIMEOUT : REQ_TIMEOUT, request_timeout, session); return 0; failed: g_free(req->data); g_free(req); return err; } static int send_request(struct avdtp *session, gboolean priority, struct avdtp_stream *stream, uint8_t signal_id, void *buffer, size_t size) { struct pending_req *req; if (stream && stream->abort_int && signal_id != AVDTP_ABORT) { DBG("Unable to send requests while aborting"); return -EINVAL; } req = g_new0(struct pending_req, 1); req->signal_id = signal_id; req->data = g_malloc(size); memcpy(req->data, buffer, size); req->data_size = size; req->stream = stream; return send_req(session, priority, req); } static gboolean avdtp_discover_resp(struct avdtp *session, struct discover_resp *resp, int size) { int sep_count, i; uint8_t getcap_cmd; int ret = 0; gboolean getcap_pending = FALSE; if (session->version >= 0x0103 && session->server->version >= 0x0103) getcap_cmd = AVDTP_GET_ALL_CAPABILITIES; else getcap_cmd = AVDTP_GET_CAPABILITIES; sep_count = size / sizeof(struct seid_info); for (i = 0; i < sep_count; i++) { struct avdtp_remote_sep *sep; struct avdtp_stream *stream; struct seid_req req; DBG("seid %d type %d media %d in use %d", resp->seps[i].seid, resp->seps[i].type, resp->seps[i].media_type, resp->seps[i].inuse); stream = find_stream_by_rseid(session, resp->seps[i].seid); sep = find_remote_sep(session->seps, resp->seps[i].seid); if (!sep) { if (resp->seps[i].inuse && !stream) continue; sep = g_new0(struct avdtp_remote_sep, 1); session->seps = g_slist_append(session->seps, sep); } sep->stream = stream; sep->seid = resp->seps[i].seid; sep->type = resp->seps[i].type; sep->media_type = resp->seps[i].media_type; memset(&req, 0, sizeof(req)); req.acp_seid = sep->seid; ret = send_request(session, TRUE, NULL, getcap_cmd, &req, sizeof(req)); if (ret < 0) break; getcap_pending = TRUE; } if (!getcap_pending) finalize_discovery(session, -ret); return TRUE; } static gboolean avdtp_get_capabilities_resp(struct avdtp *session, struct getcap_resp *resp, unsigned int size) { struct avdtp_remote_sep *sep; uint8_t seid; /* Check for minimum required packet size includes: * 1. getcap resp header * 2. media transport capability (2 bytes) * 3. media codec capability type + length (2 bytes) * 4. the actual media codec elements * */ if (size < (sizeof(struct getcap_resp) + 4 + sizeof(struct avdtp_media_codec_capability))) { error("Too short getcap resp packet"); return FALSE; } seid = ((struct seid_req *) session->req->data)->acp_seid; sep = find_remote_sep(session->seps, seid); DBG("seid %d type %d media %d", sep->seid, sep->type, sep->media_type); if (sep->caps) { g_slist_free_full(sep->caps, g_free); sep->caps = NULL; sep->codec = NULL; sep->delay_reporting = FALSE; } sep->caps = caps_to_list(resp->caps, size - sizeof(struct getcap_resp), &sep->codec, &sep->delay_reporting); return TRUE; } static gboolean avdtp_set_configuration_resp(struct avdtp *session, struct avdtp_stream *stream, struct avdtp_single_header *resp, int size) { struct avdtp_local_sep *sep = stream->lsep; if (sep->cfm && sep->cfm->set_configuration) sep->cfm->set_configuration(session, sep, stream, NULL, sep->user_data); avdtp_sep_set_state(session, sep, AVDTP_STATE_CONFIGURED); return TRUE; } static gboolean avdtp_reconfigure_resp(struct avdtp *session, struct avdtp_stream *stream, struct avdtp_single_header *resp, int size) { return TRUE; } static gboolean avdtp_open_resp(struct avdtp *session, struct avdtp_stream *stream, struct seid_rej *resp, int size) { struct avdtp_local_sep *sep = stream->lsep; stream->io = l2cap_connect(session); if (!stream->io) { avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE); return FALSE; } session->pending_open = stream; return TRUE; } static gboolean avdtp_start_resp(struct avdtp *session, struct avdtp_stream *stream, struct seid_rej *resp, int size) { struct avdtp_local_sep *sep = stream->lsep; if (sep->cfm && sep->cfm->start) sep->cfm->start(session, sep, stream, NULL, sep->user_data); /* We might be in STREAMING already if both sides send START_CMD at the * same time and the one in SNK role doesn't reject it as it should */ if (sep->state != AVDTP_STATE_STREAMING) avdtp_sep_set_state(session, sep, AVDTP_STATE_STREAMING); return TRUE; } static gboolean avdtp_close_resp(struct avdtp *session, struct avdtp_stream *stream, struct seid_rej *resp, int size) { struct avdtp_local_sep *sep = stream->lsep; avdtp_sep_set_state(session, sep, AVDTP_STATE_CLOSING); close_stream(stream); return TRUE; } static gboolean avdtp_suspend_resp(struct avdtp *session, struct avdtp_stream *stream, void *data, int size) { struct avdtp_local_sep *sep = stream->lsep; avdtp_sep_set_state(session, sep, AVDTP_STATE_OPEN); if (sep->cfm && sep->cfm->suspend) sep->cfm->suspend(session, sep, stream, NULL, sep->user_data); return TRUE; } static gboolean avdtp_abort_resp(struct avdtp *session, struct avdtp_stream *stream, struct seid_rej *resp, int size) { struct avdtp_local_sep *sep = stream->lsep; avdtp_sep_set_state(session, sep, AVDTP_STATE_ABORTING); if (sep->cfm && sep->cfm->abort) sep->cfm->abort(session, sep, stream, NULL, sep->user_data); avdtp_sep_set_state(session, sep, AVDTP_STATE_IDLE); return TRUE; } static gboolean avdtp_delay_report_resp(struct avdtp *session, struct avdtp_stream *stream, void *data, int size) { struct avdtp_local_sep *sep = stream->lsep; if (sep->cfm && sep->cfm->delay_report) sep->cfm->delay_report(session, sep, stream, NULL, sep->user_data); return TRUE; } static gboolean avdtp_parse_resp(struct avdtp *session, struct avdtp_stream *stream, uint8_t transaction, uint8_t signal_id, void *buf, int size) { struct pending_req *next; const char *get_all = ""; if (session->prio_queue) next = session->prio_queue->data; else if (session->req_queue) next = session->req_queue->data; else next = NULL; switch (signal_id) { case AVDTP_DISCOVER: DBG("DISCOVER request succeeded"); return avdtp_discover_resp(session, buf, size); case AVDTP_GET_ALL_CAPABILITIES: get_all = "ALL_"; case AVDTP_GET_CAPABILITIES: DBG("GET_%sCAPABILITIES request succeeded", get_all); if (!avdtp_get_capabilities_resp(session, buf, size)) return FALSE; if (!(next && (next->signal_id == AVDTP_GET_CAPABILITIES || next->signal_id == AVDTP_GET_ALL_CAPABILITIES))) finalize_discovery(session, 0); return TRUE; } /* The remaining commands require an existing stream so bail out * here if the stream got unexpectedly disconnected */ if (!stream) { DBG("AVDTP: stream was closed while waiting for reply"); return TRUE; } switch (signal_id) { case AVDTP_SET_CONFIGURATION: DBG("SET_CONFIGURATION request succeeded"); return avdtp_set_configuration_resp(session, stream, buf, size); case AVDTP_RECONFIGURE: DBG("RECONFIGURE request succeeded"); return avdtp_reconfigure_resp(session, stream, buf, size); case AVDTP_OPEN: DBG("OPEN request succeeded"); return avdtp_open_resp(session, stream, buf, size); case AVDTP_SUSPEND: DBG("SUSPEND request succeeded"); return avdtp_suspend_resp(session, stream, buf, size); case AVDTP_START: DBG("START request succeeded"); return avdtp_start_resp(session, stream, buf, size); case AVDTP_CLOSE: DBG("CLOSE request succeeded"); return avdtp_close_resp(session, stream, buf, size); case AVDTP_ABORT: DBG("ABORT request succeeded"); return avdtp_abort_resp(session, stream, buf, size); case AVDTP_DELAY_REPORT: DBG("DELAY_REPORT request succeeded"); return avdtp_delay_report_resp(session, stream, buf, size); } error("Unknown signal id in accept response: %u", signal_id); return TRUE; } static gboolean seid_rej_to_err(struct seid_rej *rej, unsigned int size, struct avdtp_error *err) { if (size < sizeof(struct seid_rej)) { error("Too small packet for seid_rej"); return FALSE; } avdtp_error_init(err, 0x00, rej->error); return TRUE; } static gboolean conf_rej_to_err(struct conf_rej *rej, unsigned int size, struct avdtp_error *err) { if (size < sizeof(struct conf_rej)) { error("Too small packet for conf_rej"); return FALSE; } avdtp_error_init(err, rej->category, rej->error); return TRUE; } static gboolean stream_rej_to_err(struct stream_rej *rej, unsigned int size, struct avdtp_error *err, uint8_t *acp_seid) { if (size < sizeof(struct stream_rej)) { error("Too small packet for stream_rej"); return FALSE; } avdtp_error_init(err, 0x00, rej->error); if (acp_seid) *acp_seid = rej->acp_seid; return TRUE; } static gboolean avdtp_parse_rej(struct avdtp *session, struct avdtp_stream *stream, uint8_t transaction, uint8_t signal_id, void *buf, int size) { struct avdtp_error err; uint8_t acp_seid; struct avdtp_local_sep *sep = stream ? stream->lsep : NULL; switch (signal_id) { case AVDTP_DISCOVER: if (!seid_rej_to_err(buf, size, &err)) return FALSE; error("DISCOVER request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); return TRUE; case AVDTP_GET_CAPABILITIES: case AVDTP_GET_ALL_CAPABILITIES: if (!seid_rej_to_err(buf, size, &err)) return FALSE; error("GET_CAPABILITIES request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); return TRUE; case AVDTP_OPEN: if (!seid_rej_to_err(buf, size, &err)) return FALSE; error("OPEN request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); if (sep && sep->cfm && sep->cfm->open) sep->cfm->open(session, sep, stream, &err, sep->user_data); return TRUE; case AVDTP_SET_CONFIGURATION: if (!conf_rej_to_err(buf, size, &err)) return FALSE; error("SET_CONFIGURATION request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); if (sep && sep->cfm && sep->cfm->set_configuration) sep->cfm->set_configuration(session, sep, stream, &err, sep->user_data); return TRUE; case AVDTP_RECONFIGURE: if (!conf_rej_to_err(buf, size, &err)) return FALSE; error("RECONFIGURE request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); if (sep && sep->cfm && sep->cfm->reconfigure) sep->cfm->reconfigure(session, sep, stream, &err, sep->user_data); return TRUE; case AVDTP_START: if (!stream_rej_to_err(buf, size, &err, &acp_seid)) return FALSE; error("START request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); if (sep && sep->cfm && sep->cfm->start) { sep->cfm->start(session, sep, stream, &err, sep->user_data); stream->starting = FALSE; } return TRUE; case AVDTP_SUSPEND: if (!stream_rej_to_err(buf, size, &err, &acp_seid)) return FALSE; error("SUSPEND request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); if (sep && sep->cfm && sep->cfm->suspend) sep->cfm->suspend(session, sep, stream, &err, sep->user_data); return TRUE; case AVDTP_CLOSE: if (!stream_rej_to_err(buf, size, &err, &acp_seid)) return FALSE; error("CLOSE request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); if (sep && sep->cfm && sep->cfm->close) { sep->cfm->close(session, sep, stream, &err, sep->user_data); stream->close_int = FALSE; } return TRUE; case AVDTP_ABORT: if (!stream_rej_to_err(buf, size, &err, &acp_seid)) return FALSE; error("ABORT request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); if (sep && sep->cfm && sep->cfm->abort) sep->cfm->abort(session, sep, stream, &err, sep->user_data); return FALSE; case AVDTP_DELAY_REPORT: if (!stream_rej_to_err(buf, size, &err, &acp_seid)) return FALSE; error("DELAY_REPORT request rejected: %s (%d)", avdtp_strerror(&err), err.err.error_code); if (sep && sep->cfm && sep->cfm->delay_report) sep->cfm->delay_report(session, sep, stream, &err, sep->user_data); return TRUE; default: error("Unknown reject response signal id: %u", signal_id); return TRUE; } } gboolean avdtp_is_connected(const bdaddr_t *src, const bdaddr_t *dst) { struct avdtp_server *server; struct avdtp *session; server = find_server(servers, src); if (!server) return FALSE; session = find_session(server->sessions, dst); if (!session) return FALSE; if (session->state != AVDTP_SESSION_STATE_DISCONNECTED) return TRUE; return FALSE; } struct avdtp_service_capability *avdtp_stream_get_codec( struct avdtp_stream *stream) { GSList *l; for (l = stream->caps; l; l = l->next) { struct avdtp_service_capability *cap = l->data; if (cap->category == AVDTP_MEDIA_CODEC) return cap; } return NULL; } gboolean avdtp_stream_has_capability(struct avdtp_stream *stream, struct avdtp_service_capability *cap) { GSList *l; struct avdtp_service_capability *stream_cap; for (l = stream->caps; l; l = g_slist_next(l)) { stream_cap = l->data; if (stream_cap->category != cap->category || stream_cap->length != cap->length) continue; if (memcmp(stream_cap->data, cap->data, cap->length) == 0) return TRUE; } return FALSE; } gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream, GSList *caps) { for (; caps; caps = g_slist_next(caps)) { struct avdtp_service_capability *cap = caps->data; if (!avdtp_stream_has_capability(stream, cap)) return FALSE; } return TRUE; } struct avdtp_remote_sep *avdtp_stream_get_remote_sep( struct avdtp_stream *stream) { return avdtp_get_remote_sep(stream->session, stream->rseid); } gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock, uint16_t *imtu, uint16_t *omtu, GSList **caps) { if (stream->io == NULL) return FALSE; if (sock) *sock = g_io_channel_unix_get_fd(stream->io); if (omtu) *omtu = stream->omtu; if (imtu) *imtu = stream->imtu; if (caps) *caps = stream->caps; return TRUE; } static int process_queue(struct avdtp *session) { GSList **queue, *l; struct pending_req *req; if (session->req) return 0; if (session->prio_queue) queue = &session->prio_queue; else queue = &session->req_queue; if (!*queue) return 0; l = *queue; req = l->data; *queue = g_slist_remove(*queue, req); return send_req(session, FALSE, req); } struct avdtp_remote_sep *avdtp_get_remote_sep(struct avdtp *session, uint8_t seid) { GSList *l; for (l = session->seps; l; l = l->next) { struct avdtp_remote_sep *sep = l->data; if (sep->seid == seid) return sep; } return NULL; } uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep) { return sep->seid; } uint8_t avdtp_get_type(struct avdtp_remote_sep *sep) { return sep->type; } struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep) { return sep->codec; } gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep) { return sep->delay_reporting; } struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep) { return sep->stream; } struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category, void *data, int length) { struct avdtp_service_capability *cap; if (category < AVDTP_MEDIA_TRANSPORT || category > AVDTP_DELAY_REPORTING) return NULL; cap = g_malloc(sizeof(struct avdtp_service_capability) + length); cap->category = category; cap->length = length; memcpy(cap->data, data, length); return cap; } static gboolean process_discover(gpointer data) { struct avdtp *session = data; finalize_discovery(session, 0); return FALSE; } int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb, void *user_data) { int err; if (session->discov_cb) return -EBUSY; if (session->seps) { session->discov_cb = cb; session->user_data = user_data; g_idle_add(process_discover, session); return 0; } err = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0); if (err == 0) { session->discov_cb = cb; session->user_data = user_data; } return err; } gboolean avdtp_stream_remove_cb(struct avdtp *session, struct avdtp_stream *stream, unsigned int id) { GSList *l; struct stream_callback *cb; if (!stream) return FALSE; for (cb = NULL, l = stream->callbacks; l != NULL; l = l->next) { struct stream_callback *tmp = l->data; if (tmp && tmp->id == id) { cb = tmp; break; } } if (!cb) return FALSE; stream->callbacks = g_slist_remove(stream->callbacks, cb); g_free(cb); return TRUE; } unsigned int avdtp_stream_add_cb(struct avdtp *session, struct avdtp_stream *stream, avdtp_stream_state_cb cb, void *data) { struct stream_callback *stream_cb; static unsigned int id = 0; stream_cb = g_new(struct stream_callback, 1); stream_cb->cb = cb; stream_cb->user_data = data; stream_cb->id = ++id; stream->callbacks = g_slist_append(stream->callbacks, stream_cb); return stream_cb->id; } int avdtp_get_configuration(struct avdtp *session, struct avdtp_stream *stream) { struct seid_req req; if (session->state < AVDTP_SESSION_STATE_CONNECTED) return -EINVAL; memset(&req, 0, sizeof(req)); req.acp_seid = stream->rseid; return send_request(session, FALSE, stream, AVDTP_GET_CONFIGURATION, &req, sizeof(req)); } static void copy_capabilities(gpointer data, gpointer user_data) { struct avdtp_service_capability *src_cap = data; struct avdtp_service_capability *dst_cap; GSList **l = user_data; dst_cap = avdtp_service_cap_new(src_cap->category, src_cap->data, src_cap->length); *l = g_slist_append(*l, dst_cap); } int avdtp_set_configuration(struct avdtp *session, struct avdtp_remote_sep *rsep, struct avdtp_local_sep *lsep, GSList *caps, struct avdtp_stream **stream) { struct setconf_req *req; struct avdtp_stream *new_stream; unsigned char *ptr; int err, caps_len; struct avdtp_service_capability *cap; GSList *l; if (session->state != AVDTP_SESSION_STATE_CONNECTED) return -ENOTCONN; if (!(lsep && rsep)) return -EINVAL; DBG("%p: int_seid=%u, acp_seid=%u", session, lsep->info.seid, rsep->seid); new_stream = g_new0(struct avdtp_stream, 1); new_stream->session = session; new_stream->lsep = lsep; new_stream->rseid = rsep->seid; if (rsep->delay_reporting && lsep->delay_reporting) { struct avdtp_service_capability *delay_reporting; delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING, NULL, 0); caps = g_slist_append(caps, delay_reporting); new_stream->delay_reporting = TRUE; } g_slist_foreach(caps, copy_capabilities, &new_stream->caps); /* Calculate total size of request */ for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) { cap = l->data; caps_len += cap->length + 2; } req = g_malloc0(sizeof(struct setconf_req) + caps_len); req->int_seid = lsep->info.seid; req->acp_seid = rsep->seid; /* Copy the capabilities into the request */ for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) { cap = l->data; memcpy(ptr, cap, cap->length + 2); ptr += cap->length + 2; } err = send_request(session, FALSE, new_stream, AVDTP_SET_CONFIGURATION, req, sizeof(struct setconf_req) + caps_len); if (err < 0) stream_free(new_stream); else { lsep->info.inuse = 1; lsep->stream = new_stream; rsep->stream = new_stream; session->streams = g_slist_append(session->streams, new_stream); if (stream) *stream = new_stream; } g_free(req); return err; } int avdtp_reconfigure(struct avdtp *session, GSList *caps, struct avdtp_stream *stream) { struct reconf_req *req; unsigned char *ptr; int caps_len, err; GSList *l; struct avdtp_service_capability *cap; if (!g_slist_find(session->streams, stream)) return -EINVAL; if (stream->lsep->state != AVDTP_STATE_OPEN) return -EINVAL; /* Calculate total size of request */ for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) { cap = l->data; caps_len += cap->length + 2; } req = g_malloc0(sizeof(struct reconf_req) + caps_len); req->acp_seid = stream->rseid; /* Copy the capabilities into the request */ for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) { cap = l->data; memcpy(ptr, cap, cap->length + 2); ptr += cap->length + 2; } err = send_request(session, FALSE, stream, AVDTP_RECONFIGURE, req, sizeof(*req) + caps_len); g_free(req); return err; } int avdtp_open(struct avdtp *session, struct avdtp_stream *stream) { struct seid_req req; if (!g_slist_find(session->streams, stream)) return -EINVAL; if (stream->lsep->state > AVDTP_STATE_CONFIGURED) return -EINVAL; memset(&req, 0, sizeof(req)); req.acp_seid = stream->rseid; return send_request(session, FALSE, stream, AVDTP_OPEN, &req, sizeof(req)); } int avdtp_start(struct avdtp *session, struct avdtp_stream *stream) { struct start_req req; int ret; if (!g_slist_find(session->streams, stream)) return -EINVAL; if (stream->lsep->state != AVDTP_STATE_OPEN) return -EINVAL; /* Recommendation 12: * If the RD has configured and opened a stream it is also responsible * to start the streaming via GAVDP_START. */ if (stream->open_acp) { stream->starting = TRUE; return 0; } if (stream->close_int == TRUE) { error("avdtp_start: rejecting start since close is initiated"); return -EINVAL; } if (stream->starting == TRUE) { DBG("stream already started"); return -EINPROGRESS; } memset(&req, 0, sizeof(req)); req.first_seid.seid = stream->rseid; ret = send_request(session, FALSE, stream, AVDTP_START, &req, sizeof(req)); if (ret == 0) stream->starting = TRUE; return ret; } int avdtp_close(struct avdtp *session, struct avdtp_stream *stream, gboolean immediate) { struct seid_req req; int ret; if (!g_slist_find(session->streams, stream)) return -EINVAL; if (stream->lsep->state < AVDTP_STATE_OPEN) return -EINVAL; if (stream->close_int == TRUE) { error("avdtp_close: rejecting since close is already initiated"); return -EINVAL; } if (immediate && session->req && stream == session->req->stream) return avdtp_abort(session, stream); memset(&req, 0, sizeof(req)); req.acp_seid = stream->rseid; ret = send_request(session, FALSE, stream, AVDTP_CLOSE, &req, sizeof(req)); if (ret == 0) stream->close_int = TRUE; return ret; } int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream) { struct seid_req req; if (!g_slist_find(session->streams, stream)) return -EINVAL; if (stream->lsep->state <= AVDTP_STATE_OPEN || stream->close_int) return -EINVAL; memset(&req, 0, sizeof(req)); req.acp_seid = stream->rseid; return send_request(session, FALSE, stream, AVDTP_SUSPEND, &req, sizeof(req)); } int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream) { struct seid_req req; int ret; if (!g_slist_find(session->streams, stream)) return -EINVAL; if (stream->lsep->state == AVDTP_STATE_ABORTING) return -EINVAL; if (session->req && stream == session->req->stream) return cancel_request(session, ECANCELED); memset(&req, 0, sizeof(req)); req.acp_seid = stream->rseid; ret = send_request(session, TRUE, stream, AVDTP_ABORT, &req, sizeof(req)); if (ret == 0) stream->abort_int = TRUE; return ret; } int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream, uint16_t delay) { struct delay_req req; if (!g_slist_find(session->streams, stream)) return -EINVAL; if (stream->lsep->state != AVDTP_STATE_CONFIGURED && stream->lsep->state != AVDTP_STATE_STREAMING) return -EINVAL; if (!stream->delay_reporting || session->version < 0x0103 || session->server->version < 0x0103) return -EINVAL; stream->delay = delay; memset(&req, 0, sizeof(req)); req.acp_seid = stream->rseid; req.delay = htons(delay); return send_request(session, TRUE, stream, AVDTP_DELAY_REPORT, &req, sizeof(req)); } struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type, uint8_t media_type, uint8_t codec_type, gboolean delay_reporting, struct avdtp_sep_ind *ind, struct avdtp_sep_cfm *cfm, void *user_data) { struct avdtp_server *server; struct avdtp_local_sep *sep; server = find_server(servers, src); if (!server) return NULL; if (g_slist_length(server->seps) > MAX_SEID) return NULL; sep = g_new0(struct avdtp_local_sep, 1); sep->state = AVDTP_STATE_IDLE; sep->info.seid = g_slist_length(server->seps) + 1; sep->info.type = type; sep->info.media_type = media_type; sep->codec = codec_type; sep->ind = ind; sep->cfm = cfm; sep->user_data = user_data; sep->server = server; sep->delay_reporting = TRUE; DBG("SEP %p registered: type:%d codec:%d seid:%d", sep, sep->info.type, sep->codec, sep->info.seid); server->seps = g_slist_append(server->seps, sep); return sep; } int avdtp_unregister_sep(struct avdtp_local_sep *sep) { struct avdtp_server *server; if (!sep) return -EINVAL; server = sep->server; server->seps = g_slist_remove(server->seps, sep); if (sep->stream) release_stream(sep->stream, sep->stream->session); DBG("SEP %p unregistered: type:%d codec:%d seid:%d", sep, sep->info.type, sep->codec, sep->info.seid); g_free(sep); return 0; } static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master) { GError *err = NULL; GIOChannel *io; io = bt_io_listen(BT_IO_L2CAP, NULL, avdtp_confirm_cb, NULL, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_PSM, AVDTP_PSM, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_MASTER, master, BT_IO_OPT_INVALID); if (!io) { error("%s", err->message); g_error_free(err); } return io; } const char *avdtp_strerror(struct avdtp_error *err) { if (err->category == AVDTP_ERRNO) return strerror(err->err.posix_errno); switch(err->err.error_code) { case AVDTP_BAD_HEADER_FORMAT: return "Bad Header Format"; case AVDTP_BAD_LENGTH: return "Bad Packet Length"; case AVDTP_BAD_ACP_SEID: return "Bad Acceptor SEID"; case AVDTP_SEP_IN_USE: return "Stream End Point in Use"; case AVDTP_SEP_NOT_IN_USE: return "Stream End Point Not in Use"; case AVDTP_BAD_SERV_CATEGORY: return "Bad Service Category"; case AVDTP_BAD_PAYLOAD_FORMAT: return "Bad Payload format"; case AVDTP_NOT_SUPPORTED_COMMAND: return "Command Not Supported"; case AVDTP_INVALID_CAPABILITIES: return "Invalid Capabilities"; case AVDTP_BAD_RECOVERY_TYPE: return "Bad Recovery Type"; case AVDTP_BAD_MEDIA_TRANSPORT_FORMAT: return "Bad Media Transport Format"; case AVDTP_BAD_RECOVERY_FORMAT: return "Bad Recovery Format"; case AVDTP_BAD_ROHC_FORMAT: return "Bad Header Compression Format"; case AVDTP_BAD_CP_FORMAT: return "Bad Content Protetion Format"; case AVDTP_BAD_MULTIPLEXING_FORMAT: return "Bad Multiplexing Format"; case AVDTP_UNSUPPORTED_CONFIGURATION: return "Configuration not supported"; case AVDTP_BAD_STATE: return "Bad State"; default: return "Unknow error"; } } avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep) { return sep->state; } void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst) { if (src) bacpy(src, &session->server->src); if (dst) bacpy(dst, &session->dst); } int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version) { GError *err = NULL; gboolean tmp, master = TRUE; struct avdtp_server *server; uint16_t ver = 0x0102; if (!config) goto proceed; tmp = g_key_file_get_boolean(config, "General", "Master", &err); if (err) { DBG("audio.conf: %s", err->message); g_clear_error(&err); } else master = tmp; tmp = g_key_file_get_boolean(config, "General", "AutoConnect", &err); if (err) g_clear_error(&err); else auto_connect = tmp; if (g_key_file_get_boolean(config, "A2DP", "DelayReporting", NULL)) ver = 0x0103; proceed: server = g_new0(struct avdtp_server, 1); if (!server) return -ENOMEM; server->version = ver; if (version) *version = server->version; server->io = avdtp_server_socket(src, master); if (!server->io) { g_free(server); return -1; } bacpy(&server->src, src); servers = g_slist_append(servers, server); return 0; } void avdtp_exit(const bdaddr_t *src) { struct avdtp_server *server; GSList *l; server = find_server(servers, src); if (!server) return; l = server->sessions; while (l) { struct avdtp *session = l->data; l = l->next; /* value of l pointer should be updated before invoking * connection_lost since it internally uses avdtp_unref * which operates on server->session list as well */ connection_lost(session, -ECONNABORTED); } servers = g_slist_remove(servers, server); g_io_channel_shutdown(server->io, TRUE, NULL); g_io_channel_unref(server->io); g_free(server); } gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream) { return g_slist_find(session->streams, stream) ? TRUE : FALSE; } void avdtp_set_auto_disconnect(struct avdtp *session, gboolean auto_dc) { session->auto_dc = auto_dc; } gboolean avdtp_stream_setup_active(struct avdtp *session) { return session->stream_setup; } void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc) { session->device_disconnect = dev_dc; } unsigned int avdtp_add_state_cb(avdtp_session_state_cb cb, void *user_data) { struct avdtp_state_callback *state_cb; static unsigned int id = 0; state_cb = g_new(struct avdtp_state_callback, 1); state_cb->cb = cb; state_cb->user_data = user_data; state_cb->id = ++id; avdtp_callbacks = g_slist_append(avdtp_callbacks, state_cb); return state_cb->id; } gboolean avdtp_remove_state_cb(unsigned int id) { GSList *l; for (l = avdtp_callbacks; l != NULL; l = l->next) { struct avdtp_state_callback *cb = l->data; if (cb && cb->id == id) { avdtp_callbacks = g_slist_remove(avdtp_callbacks, cb); g_free(cb); return TRUE; } } return FALSE; } bluez-4.101/audio/gstrtpsbcpay.h0000644000000000000000000000360311571052274013534 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include G_BEGIN_DECLS #define GST_TYPE_RTP_SBC_PAY \ (gst_rtp_sbc_pay_get_type()) #define GST_RTP_SBC_PAY(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SBC_PAY,\ GstRtpSBCPay)) #define GST_RTP_SBC_PAY_CLASS(klass) \ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SBC_PAY,\ GstRtpSBCPayClass)) #define GST_IS_RTP_SBC_PAY(obj) \ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SBC_PAY)) #define GST_IS_RTP_SBC_PAY_CLASS(obj) \ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SBC_PAY)) typedef struct _GstRtpSBCPay GstRtpSBCPay; typedef struct _GstRtpSBCPayClass GstRtpSBCPayClass; struct _GstRtpSBCPay { GstBaseRTPPayload base; GstAdapter *adapter; GstClockTime timestamp; guint frame_length; guint min_frames; }; struct _GstRtpSBCPayClass { GstBaseRTPPayloadClass parent_class; }; GType gst_rtp_sbc_pay_get_type(void); gboolean gst_rtp_sbc_pay_plugin_init (GstPlugin * plugin); G_END_DECLS bluez-4.101/audio/control.h0000644000000000000000000000226311766125764012503 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define AUDIO_CONTROL_INTERFACE "org.bluez.Control" struct control *control_init(struct audio_device *dev, uint16_t uuid16); void control_update(struct control *control, uint16_t uuid16); void control_unregister(struct audio_device *dev); gboolean control_is_active(struct audio_device *dev); bluez-4.101/sbc/0000755000000000000000000000000011771120004010347 500000000000000bluez-4.101/sbc/sbc_math.h0000644000000000000000000000427711571052274012245 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2008 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define fabs(x) ((x) < 0 ? -(x) : (x)) /* C does not provide an explicit arithmetic shift right but this will always be correct and every compiler *should* generate optimal code */ #define ASR(val, bits) ((-2 >> 1 == -1) ? \ ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits))) #define SCALE_SPROTO4_TBL 12 #define SCALE_SPROTO8_TBL 14 #define SCALE_NPROTO4_TBL 11 #define SCALE_NPROTO8_TBL 11 #define SCALE4_STAGED1_BITS 15 #define SCALE4_STAGED2_BITS 16 #define SCALE8_STAGED1_BITS 15 #define SCALE8_STAGED2_BITS 16 typedef int32_t sbc_fixed_t; #define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS) #define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS) #define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS) #define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS) #define SBC_FIXED_0(val) { val = 0; } #define MUL(a, b) ((a) * (b)) #if defined(__arm__) && (!defined(__thumb__) || defined(__thumb2__)) #define MULA(a, b, res) ({ \ int tmp = res; \ __asm__( \ "mla %0, %2, %3, %0" \ : "=&r" (tmp) \ : "0" (tmp), "r" (a), "r" (b)); \ tmp; }) #else #define MULA(a, b, res) ((a) * (b) + (res)) #endif bluez-4.101/sbc/sbc_primitives_mmx.c0000644000000000000000000002410411766125764014365 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "sbc.h" #include "sbc_math.h" #include "sbc_tables.h" #include "sbc_primitives_mmx.h" /* * MMX optimizations */ #ifdef SBC_BUILD_WITH_MMX_SUPPORT static inline void sbc_analyze_four_mmx(const int16_t *in, int32_t *out, const FIXED_T *consts) { static const SBC_ALIGNED int32_t round_c[2] = { 1 << (SBC_PROTO_FIXED4_SCALE - 1), 1 << (SBC_PROTO_FIXED4_SCALE - 1), }; __asm__ volatile ( "movq (%0), %%mm0\n" "movq 8(%0), %%mm1\n" "pmaddwd (%1), %%mm0\n" "pmaddwd 8(%1), %%mm1\n" "paddd (%2), %%mm0\n" "paddd (%2), %%mm1\n" "\n" "movq 16(%0), %%mm2\n" "movq 24(%0), %%mm3\n" "pmaddwd 16(%1), %%mm2\n" "pmaddwd 24(%1), %%mm3\n" "paddd %%mm2, %%mm0\n" "paddd %%mm3, %%mm1\n" "\n" "movq 32(%0), %%mm2\n" "movq 40(%0), %%mm3\n" "pmaddwd 32(%1), %%mm2\n" "pmaddwd 40(%1), %%mm3\n" "paddd %%mm2, %%mm0\n" "paddd %%mm3, %%mm1\n" "\n" "movq 48(%0), %%mm2\n" "movq 56(%0), %%mm3\n" "pmaddwd 48(%1), %%mm2\n" "pmaddwd 56(%1), %%mm3\n" "paddd %%mm2, %%mm0\n" "paddd %%mm3, %%mm1\n" "\n" "movq 64(%0), %%mm2\n" "movq 72(%0), %%mm3\n" "pmaddwd 64(%1), %%mm2\n" "pmaddwd 72(%1), %%mm3\n" "paddd %%mm2, %%mm0\n" "paddd %%mm3, %%mm1\n" "\n" "psrad %4, %%mm0\n" "psrad %4, %%mm1\n" "packssdw %%mm0, %%mm0\n" "packssdw %%mm1, %%mm1\n" "\n" "movq %%mm0, %%mm2\n" "pmaddwd 80(%1), %%mm0\n" "pmaddwd 88(%1), %%mm2\n" "\n" "movq %%mm1, %%mm3\n" "pmaddwd 96(%1), %%mm1\n" "pmaddwd 104(%1), %%mm3\n" "paddd %%mm1, %%mm0\n" "paddd %%mm3, %%mm2\n" "\n" "movq %%mm0, (%3)\n" "movq %%mm2, 8(%3)\n" : : "r" (in), "r" (consts), "r" (&round_c), "r" (out), "i" (SBC_PROTO_FIXED4_SCALE) : "cc", "memory"); } static inline void sbc_analyze_eight_mmx(const int16_t *in, int32_t *out, const FIXED_T *consts) { static const SBC_ALIGNED int32_t round_c[2] = { 1 << (SBC_PROTO_FIXED8_SCALE - 1), 1 << (SBC_PROTO_FIXED8_SCALE - 1), }; __asm__ volatile ( "movq (%0), %%mm0\n" "movq 8(%0), %%mm1\n" "movq 16(%0), %%mm2\n" "movq 24(%0), %%mm3\n" "pmaddwd (%1), %%mm0\n" "pmaddwd 8(%1), %%mm1\n" "pmaddwd 16(%1), %%mm2\n" "pmaddwd 24(%1), %%mm3\n" "paddd (%2), %%mm0\n" "paddd (%2), %%mm1\n" "paddd (%2), %%mm2\n" "paddd (%2), %%mm3\n" "\n" "movq 32(%0), %%mm4\n" "movq 40(%0), %%mm5\n" "movq 48(%0), %%mm6\n" "movq 56(%0), %%mm7\n" "pmaddwd 32(%1), %%mm4\n" "pmaddwd 40(%1), %%mm5\n" "pmaddwd 48(%1), %%mm6\n" "pmaddwd 56(%1), %%mm7\n" "paddd %%mm4, %%mm0\n" "paddd %%mm5, %%mm1\n" "paddd %%mm6, %%mm2\n" "paddd %%mm7, %%mm3\n" "\n" "movq 64(%0), %%mm4\n" "movq 72(%0), %%mm5\n" "movq 80(%0), %%mm6\n" "movq 88(%0), %%mm7\n" "pmaddwd 64(%1), %%mm4\n" "pmaddwd 72(%1), %%mm5\n" "pmaddwd 80(%1), %%mm6\n" "pmaddwd 88(%1), %%mm7\n" "paddd %%mm4, %%mm0\n" "paddd %%mm5, %%mm1\n" "paddd %%mm6, %%mm2\n" "paddd %%mm7, %%mm3\n" "\n" "movq 96(%0), %%mm4\n" "movq 104(%0), %%mm5\n" "movq 112(%0), %%mm6\n" "movq 120(%0), %%mm7\n" "pmaddwd 96(%1), %%mm4\n" "pmaddwd 104(%1), %%mm5\n" "pmaddwd 112(%1), %%mm6\n" "pmaddwd 120(%1), %%mm7\n" "paddd %%mm4, %%mm0\n" "paddd %%mm5, %%mm1\n" "paddd %%mm6, %%mm2\n" "paddd %%mm7, %%mm3\n" "\n" "movq 128(%0), %%mm4\n" "movq 136(%0), %%mm5\n" "movq 144(%0), %%mm6\n" "movq 152(%0), %%mm7\n" "pmaddwd 128(%1), %%mm4\n" "pmaddwd 136(%1), %%mm5\n" "pmaddwd 144(%1), %%mm6\n" "pmaddwd 152(%1), %%mm7\n" "paddd %%mm4, %%mm0\n" "paddd %%mm5, %%mm1\n" "paddd %%mm6, %%mm2\n" "paddd %%mm7, %%mm3\n" "\n" "psrad %4, %%mm0\n" "psrad %4, %%mm1\n" "psrad %4, %%mm2\n" "psrad %4, %%mm3\n" "\n" "packssdw %%mm0, %%mm0\n" "packssdw %%mm1, %%mm1\n" "packssdw %%mm2, %%mm2\n" "packssdw %%mm3, %%mm3\n" "\n" "movq %%mm0, %%mm4\n" "movq %%mm0, %%mm5\n" "pmaddwd 160(%1), %%mm4\n" "pmaddwd 168(%1), %%mm5\n" "\n" "movq %%mm1, %%mm6\n" "movq %%mm1, %%mm7\n" "pmaddwd 192(%1), %%mm6\n" "pmaddwd 200(%1), %%mm7\n" "paddd %%mm6, %%mm4\n" "paddd %%mm7, %%mm5\n" "\n" "movq %%mm2, %%mm6\n" "movq %%mm2, %%mm7\n" "pmaddwd 224(%1), %%mm6\n" "pmaddwd 232(%1), %%mm7\n" "paddd %%mm6, %%mm4\n" "paddd %%mm7, %%mm5\n" "\n" "movq %%mm3, %%mm6\n" "movq %%mm3, %%mm7\n" "pmaddwd 256(%1), %%mm6\n" "pmaddwd 264(%1), %%mm7\n" "paddd %%mm6, %%mm4\n" "paddd %%mm7, %%mm5\n" "\n" "movq %%mm4, (%3)\n" "movq %%mm5, 8(%3)\n" "\n" "movq %%mm0, %%mm5\n" "pmaddwd 176(%1), %%mm0\n" "pmaddwd 184(%1), %%mm5\n" "\n" "movq %%mm1, %%mm7\n" "pmaddwd 208(%1), %%mm1\n" "pmaddwd 216(%1), %%mm7\n" "paddd %%mm1, %%mm0\n" "paddd %%mm7, %%mm5\n" "\n" "movq %%mm2, %%mm7\n" "pmaddwd 240(%1), %%mm2\n" "pmaddwd 248(%1), %%mm7\n" "paddd %%mm2, %%mm0\n" "paddd %%mm7, %%mm5\n" "\n" "movq %%mm3, %%mm7\n" "pmaddwd 272(%1), %%mm3\n" "pmaddwd 280(%1), %%mm7\n" "paddd %%mm3, %%mm0\n" "paddd %%mm7, %%mm5\n" "\n" "movq %%mm0, 16(%3)\n" "movq %%mm5, 24(%3)\n" : : "r" (in), "r" (consts), "r" (&round_c), "r" (out), "i" (SBC_PROTO_FIXED8_SCALE) : "cc", "memory"); } static inline void sbc_analyze_4b_4s_mmx(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ sbc_analyze_four_mmx(x + 12, out, analysis_consts_fixed4_simd_odd); out += out_stride; sbc_analyze_four_mmx(x + 8, out, analysis_consts_fixed4_simd_even); out += out_stride; sbc_analyze_four_mmx(x + 4, out, analysis_consts_fixed4_simd_odd); out += out_stride; sbc_analyze_four_mmx(x + 0, out, analysis_consts_fixed4_simd_even); __asm__ volatile ("emms\n"); } static inline void sbc_analyze_4b_8s_mmx(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ sbc_analyze_eight_mmx(x + 24, out, analysis_consts_fixed8_simd_odd); out += out_stride; sbc_analyze_eight_mmx(x + 16, out, analysis_consts_fixed8_simd_even); out += out_stride; sbc_analyze_eight_mmx(x + 8, out, analysis_consts_fixed8_simd_odd); out += out_stride; sbc_analyze_eight_mmx(x + 0, out, analysis_consts_fixed8_simd_even); __asm__ volatile ("emms\n"); } static void sbc_calc_scalefactors_mmx( int32_t sb_sample_f[16][2][8], uint32_t scale_factor[2][8], int blocks, int channels, int subbands) { static const SBC_ALIGNED int32_t consts[2] = { 1 << SCALE_OUT_BITS, 1 << SCALE_OUT_BITS, }; int ch, sb; intptr_t blk; for (ch = 0; ch < channels; ch++) { for (sb = 0; sb < subbands; sb += 2) { blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] - (char *) &sb_sample_f[0][0][0])); __asm__ volatile ( "movq (%4), %%mm0\n" "1:\n" "movq (%1, %0), %%mm1\n" "pxor %%mm2, %%mm2\n" "pcmpgtd %%mm2, %%mm1\n" "paddd (%1, %0), %%mm1\n" "pcmpgtd %%mm1, %%mm2\n" "pxor %%mm2, %%mm1\n" "por %%mm1, %%mm0\n" "sub %2, %0\n" "jns 1b\n" "movd %%mm0, %k0\n" "psrlq $32, %%mm0\n" "bsrl %k0, %k0\n" "subl %5, %k0\n" "movl %k0, (%3)\n" "movd %%mm0, %k0\n" "bsrl %k0, %k0\n" "subl %5, %k0\n" "movl %k0, 4(%3)\n" : "+r" (blk) : "r" (&sb_sample_f[0][ch][sb]), "i" ((char *) &sb_sample_f[1][0][0] - (char *) &sb_sample_f[0][0][0]), "r" (&scale_factor[ch][sb]), "r" (&consts), "i" (SCALE_OUT_BITS) : "cc", "memory"); } } __asm__ volatile ("emms\n"); } static int check_mmx_support(void) { #ifdef __amd64__ return 1; /* We assume that all 64-bit processors have MMX support */ #else int cpuid_feature_information; __asm__ volatile ( /* According to Intel manual, CPUID instruction is supported * if the value of ID bit (bit 21) in EFLAGS can be modified */ "pushf\n" "movl (%%esp), %0\n" "xorl $0x200000, (%%esp)\n" /* try to modify ID bit */ "popf\n" "pushf\n" "xorl (%%esp), %0\n" /* check if ID bit changed */ "jz 1f\n" "push %%eax\n" "push %%ebx\n" "push %%ecx\n" "mov $1, %%eax\n" "cpuid\n" "pop %%ecx\n" "pop %%ebx\n" "pop %%eax\n" "1:\n" "popf\n" : "=d" (cpuid_feature_information) : : "cc"); return cpuid_feature_information & (1 << 23); #endif } void sbc_init_primitives_mmx(struct sbc_encoder_state *state) { if (check_mmx_support()) { state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_mmx; state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_mmx; state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx; state->implementation_info = "MMX"; } } #endif bluez-4.101/sbc/sbc.h0000644000000000000000000000564311766125764011245 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __SBC_H #define __SBC_H #ifdef __cplusplus extern "C" { #endif #include #include /* sampling frequency */ #define SBC_FREQ_16000 0x00 #define SBC_FREQ_32000 0x01 #define SBC_FREQ_44100 0x02 #define SBC_FREQ_48000 0x03 /* blocks */ #define SBC_BLK_4 0x00 #define SBC_BLK_8 0x01 #define SBC_BLK_12 0x02 #define SBC_BLK_16 0x03 /* channel mode */ #define SBC_MODE_MONO 0x00 #define SBC_MODE_DUAL_CHANNEL 0x01 #define SBC_MODE_STEREO 0x02 #define SBC_MODE_JOINT_STEREO 0x03 /* allocation method */ #define SBC_AM_LOUDNESS 0x00 #define SBC_AM_SNR 0x01 /* subbands */ #define SBC_SB_4 0x00 #define SBC_SB_8 0x01 /* Data endianness */ #define SBC_LE 0x00 #define SBC_BE 0x01 struct sbc_struct { unsigned long flags; uint8_t frequency; uint8_t blocks; uint8_t subbands; uint8_t mode; uint8_t allocation; uint8_t bitpool; uint8_t endian; void *priv; void *priv_alloc_base; }; typedef struct sbc_struct sbc_t; int sbc_init(sbc_t *sbc, unsigned long flags); int sbc_reinit(sbc_t *sbc, unsigned long flags); ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len); /* Decodes ONE input block into ONE output block */ ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len, void *output, size_t output_len, size_t *written); /* Encodes ONE input block into ONE output block */ ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len, void *output, size_t output_len, ssize_t *written); /* Returns the output block size in bytes */ size_t sbc_get_frame_length(sbc_t *sbc); /* Returns the time one input/output block takes to play in msec*/ unsigned sbc_get_frame_duration(sbc_t *sbc); /* Returns the input block size in bytes */ size_t sbc_get_codesize(sbc_t *sbc); const char *sbc_get_implementation_info(sbc_t *sbc); void sbc_finish(sbc_t *sbc); #ifdef __cplusplus } #endif #endif /* __SBC_H */ bluez-4.101/sbc/sbc.c0000644000000000000000000007570711766125764011250 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2008 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* todo items: use a log2 table for byte integer scale factors calculation (sum log2 results for high and low bytes) fill bitpool by 16 bits instead of one at a time in bits allocation/bitpool generation port to the dsp */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "sbc_math.h" #include "sbc_tables.h" #include "sbc.h" #include "sbc_primitives.h" #define SBC_SYNCWORD 0x9C /* This structure contains an unpacked SBC frame. Yes, there is probably quite some unused space herein */ struct sbc_frame { uint8_t frequency; uint8_t block_mode; uint8_t blocks; enum { MONO = SBC_MODE_MONO, DUAL_CHANNEL = SBC_MODE_DUAL_CHANNEL, STEREO = SBC_MODE_STEREO, JOINT_STEREO = SBC_MODE_JOINT_STEREO } mode; uint8_t channels; enum { LOUDNESS = SBC_AM_LOUDNESS, SNR = SBC_AM_SNR } allocation; uint8_t subband_mode; uint8_t subbands; uint8_t bitpool; uint16_t codesize; uint8_t length; /* bit number x set means joint stereo has been used in subband x */ uint8_t joint; /* only the lower 4 bits of every element are to be used */ uint32_t SBC_ALIGNED scale_factor[2][8]; /* raw integer subband samples in the frame */ int32_t SBC_ALIGNED sb_sample_f[16][2][8]; /* modified subband samples */ int32_t SBC_ALIGNED sb_sample[16][2][8]; /* original pcm audio samples */ int16_t SBC_ALIGNED pcm_sample[2][16*8]; }; struct sbc_decoder_state { int subbands; int32_t V[2][170]; int offset[2][16]; }; /* * Calculates the CRC-8 of the first len bits in data */ static const uint8_t crc_table[256] = { 0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53, 0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB, 0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E, 0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76, 0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4, 0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C, 0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19, 0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1, 0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40, 0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8, 0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D, 0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65, 0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7, 0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F, 0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A, 0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2, 0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75, 0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D, 0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8, 0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50, 0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2, 0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A, 0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F, 0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7, 0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66, 0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E, 0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB, 0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43, 0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1, 0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09, 0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C, 0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4 }; static uint8_t sbc_crc8(const uint8_t *data, size_t len) { uint8_t crc = 0x0f; size_t i; uint8_t octet; for (i = 0; i < len / 8; i++) crc = crc_table[crc ^ data[i]]; octet = data[i]; for (i = 0; i < len % 8; i++) { char bit = ((octet ^ crc) & 0x80) >> 7; crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0); octet = octet << 1; } return crc; } /* * Code straight from the spec to calculate the bits array * Takes a pointer to the frame in question, a pointer to the bits array and * the sampling frequency (as 2 bit integer) */ static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal( const struct sbc_frame *frame, int (*bits)[8], int subbands) { uint8_t sf = frame->frequency; if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) { int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice; int ch, sb; for (ch = 0; ch < frame->channels; ch++) { max_bitneed = 0; if (frame->allocation == SNR) { for (sb = 0; sb < subbands; sb++) { bitneed[ch][sb] = frame->scale_factor[ch][sb]; if (bitneed[ch][sb] > max_bitneed) max_bitneed = bitneed[ch][sb]; } } else { for (sb = 0; sb < subbands; sb++) { if (frame->scale_factor[ch][sb] == 0) bitneed[ch][sb] = -5; else { if (subbands == 4) loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb]; else loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb]; if (loudness > 0) bitneed[ch][sb] = loudness / 2; else bitneed[ch][sb] = loudness; } if (bitneed[ch][sb] > max_bitneed) max_bitneed = bitneed[ch][sb]; } } bitcount = 0; slicecount = 0; bitslice = max_bitneed + 1; do { bitslice--; bitcount += slicecount; slicecount = 0; for (sb = 0; sb < subbands; sb++) { if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16)) slicecount++; else if (bitneed[ch][sb] == bitslice + 1) slicecount += 2; } } while (bitcount + slicecount < frame->bitpool); if (bitcount + slicecount == frame->bitpool) { bitcount += slicecount; bitslice--; } for (sb = 0; sb < subbands; sb++) { if (bitneed[ch][sb] < bitslice + 2) bits[ch][sb] = 0; else { bits[ch][sb] = bitneed[ch][sb] - bitslice; if (bits[ch][sb] > 16) bits[ch][sb] = 16; } } for (sb = 0; bitcount < frame->bitpool && sb < subbands; sb++) { if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) { bits[ch][sb]++; bitcount++; } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) { bits[ch][sb] = 2; bitcount += 2; } } for (sb = 0; bitcount < frame->bitpool && sb < subbands; sb++) { if (bits[ch][sb] < 16) { bits[ch][sb]++; bitcount++; } } } } else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) { int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice; int ch, sb; max_bitneed = 0; if (frame->allocation == SNR) { for (ch = 0; ch < 2; ch++) { for (sb = 0; sb < subbands; sb++) { bitneed[ch][sb] = frame->scale_factor[ch][sb]; if (bitneed[ch][sb] > max_bitneed) max_bitneed = bitneed[ch][sb]; } } } else { for (ch = 0; ch < 2; ch++) { for (sb = 0; sb < subbands; sb++) { if (frame->scale_factor[ch][sb] == 0) bitneed[ch][sb] = -5; else { if (subbands == 4) loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb]; else loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb]; if (loudness > 0) bitneed[ch][sb] = loudness / 2; else bitneed[ch][sb] = loudness; } if (bitneed[ch][sb] > max_bitneed) max_bitneed = bitneed[ch][sb]; } } } bitcount = 0; slicecount = 0; bitslice = max_bitneed + 1; do { bitslice--; bitcount += slicecount; slicecount = 0; for (ch = 0; ch < 2; ch++) { for (sb = 0; sb < subbands; sb++) { if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16)) slicecount++; else if (bitneed[ch][sb] == bitslice + 1) slicecount += 2; } } } while (bitcount + slicecount < frame->bitpool); if (bitcount + slicecount == frame->bitpool) { bitcount += slicecount; bitslice--; } for (ch = 0; ch < 2; ch++) { for (sb = 0; sb < subbands; sb++) { if (bitneed[ch][sb] < bitslice + 2) { bits[ch][sb] = 0; } else { bits[ch][sb] = bitneed[ch][sb] - bitslice; if (bits[ch][sb] > 16) bits[ch][sb] = 16; } } } ch = 0; sb = 0; while (bitcount < frame->bitpool) { if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) { bits[ch][sb]++; bitcount++; } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) { bits[ch][sb] = 2; bitcount += 2; } if (ch == 1) { ch = 0; sb++; if (sb >= subbands) break; } else ch = 1; } ch = 0; sb = 0; while (bitcount < frame->bitpool) { if (bits[ch][sb] < 16) { bits[ch][sb]++; bitcount++; } if (ch == 1) { ch = 0; sb++; if (sb >= subbands) break; } else ch = 1; } } } static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8]) { if (frame->subbands == 4) sbc_calculate_bits_internal(frame, bits, 4); else sbc_calculate_bits_internal(frame, bits, 8); } /* * Unpacks a SBC frame at the beginning of the stream in data, * which has at most len bytes into frame. * Returns the length in bytes of the packed frame, or a negative * value on error. The error codes are: * * -1 Data stream too short * -2 Sync byte incorrect * -3 CRC8 incorrect * -4 Bitpool value out of bounds */ static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame, size_t len) { unsigned int consumed; /* Will copy the parts of the header that are relevant to crc * calculation here */ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int crc_pos = 0; int32_t temp; uint32_t audio_sample; int ch, sb, blk, bit; /* channel, subband, block and bit standard counters */ int bits[2][8]; /* bits distribution */ uint32_t levels[2][8]; /* levels derived from that */ if (len < 4) return -1; if (data[0] != SBC_SYNCWORD) return -2; frame->frequency = (data[1] >> 6) & 0x03; frame->block_mode = (data[1] >> 4) & 0x03; switch (frame->block_mode) { case SBC_BLK_4: frame->blocks = 4; break; case SBC_BLK_8: frame->blocks = 8; break; case SBC_BLK_12: frame->blocks = 12; break; case SBC_BLK_16: frame->blocks = 16; break; } frame->mode = (data[1] >> 2) & 0x03; switch (frame->mode) { case MONO: frame->channels = 1; break; case DUAL_CHANNEL: /* fall-through */ case STEREO: case JOINT_STEREO: frame->channels = 2; break; } frame->allocation = (data[1] >> 1) & 0x01; frame->subband_mode = (data[1] & 0x01); frame->subbands = frame->subband_mode ? 8 : 4; frame->bitpool = data[2]; if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) && frame->bitpool > 16 * frame->subbands) return -4; if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) && frame->bitpool > 32 * frame->subbands) return -4; /* data[3] is crc, we're checking it later */ consumed = 32; crc_header[0] = data[1]; crc_header[1] = data[2]; crc_pos = 16; if (frame->mode == JOINT_STEREO) { if (len * 8 < consumed + frame->subbands) return -1; frame->joint = 0x00; for (sb = 0; sb < frame->subbands - 1; sb++) frame->joint |= ((data[4] >> (7 - sb)) & 0x01) << sb; if (frame->subbands == 4) crc_header[crc_pos / 8] = data[4] & 0xf0; else crc_header[crc_pos / 8] = data[4]; consumed += frame->subbands; crc_pos += frame->subbands; } if (len * 8 < consumed + (4 * frame->subbands * frame->channels)) return -1; for (ch = 0; ch < frame->channels; ch++) { for (sb = 0; sb < frame->subbands; sb++) { /* FIXME assert(consumed % 4 == 0); */ frame->scale_factor[ch][sb] = (data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F; crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7)); consumed += 4; crc_pos += 4; } } if (data[3] != sbc_crc8(crc_header, crc_pos)) return -3; sbc_calculate_bits(frame, bits); for (ch = 0; ch < frame->channels; ch++) { for (sb = 0; sb < frame->subbands; sb++) levels[ch][sb] = (1 << bits[ch][sb]) - 1; } for (blk = 0; blk < frame->blocks; blk++) { for (ch = 0; ch < frame->channels; ch++) { for (sb = 0; sb < frame->subbands; sb++) { uint32_t shift; if (levels[ch][sb] == 0) { frame->sb_sample[blk][ch][sb] = 0; continue; } shift = frame->scale_factor[ch][sb] + 1 + SBCDEC_FIXED_EXTRA_BITS; audio_sample = 0; for (bit = 0; bit < bits[ch][sb]; bit++) { if (consumed > len * 8) return -1; if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01) audio_sample |= 1 << (bits[ch][sb] - bit - 1); consumed++; } frame->sb_sample[blk][ch][sb] = (int32_t) (((((uint64_t) audio_sample << 1) | 1) << shift) / levels[ch][sb]) - (1 << shift); } } } if (frame->mode == JOINT_STEREO) { for (blk = 0; blk < frame->blocks; blk++) { for (sb = 0; sb < frame->subbands; sb++) { if (frame->joint & (0x01 << sb)) { temp = frame->sb_sample[blk][0][sb] + frame->sb_sample[blk][1][sb]; frame->sb_sample[blk][1][sb] = frame->sb_sample[blk][0][sb] - frame->sb_sample[blk][1][sb]; frame->sb_sample[blk][0][sb] = temp; } } } } if ((consumed & 0x7) != 0) consumed += 8 - (consumed & 0x7); return consumed >> 3; } static void sbc_decoder_init(struct sbc_decoder_state *state, const struct sbc_frame *frame) { int i, ch; memset(state->V, 0, sizeof(state->V)); state->subbands = frame->subbands; for (ch = 0; ch < 2; ch++) for (i = 0; i < frame->subbands * 2; i++) state->offset[ch][i] = (10 * i + 10); } static SBC_ALWAYS_INLINE int16_t sbc_clip16(int32_t s) { if (s > 0x7FFF) return 0x7FFF; else if (s < -0x8000) return -0x8000; else return s; } static inline void sbc_synthesize_four(struct sbc_decoder_state *state, struct sbc_frame *frame, int ch, int blk) { int i, k, idx; int32_t *v = state->V[ch]; int *offset = state->offset[ch]; for (i = 0; i < 8; i++) { /* Shifting */ offset[i]--; if (offset[i] < 0) { offset[i] = 79; memcpy(v + 80, v, 9 * sizeof(*v)); } /* Distribute the new matrix value to the shifted position */ v[offset[i]] = SCALE4_STAGED1( MULA(synmatrix4[i][0], frame->sb_sample[blk][ch][0], MULA(synmatrix4[i][1], frame->sb_sample[blk][ch][1], MULA(synmatrix4[i][2], frame->sb_sample[blk][ch][2], MUL (synmatrix4[i][3], frame->sb_sample[blk][ch][3]))))); } /* Compute the samples */ for (idx = 0, i = 0; i < 4; i++, idx += 5) { k = (i + 4) & 0xf; /* Store in output, Q0 */ frame->pcm_sample[ch][blk * 4 + i] = sbc_clip16(SCALE4_STAGED1( MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0], MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0], MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1], MULA(v[offset[k] + 3], sbc_proto_4_40m1[idx + 1], MULA(v[offset[i] + 4], sbc_proto_4_40m0[idx + 2], MULA(v[offset[k] + 5], sbc_proto_4_40m1[idx + 2], MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3], MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3], MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4], MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4])))))))))))); } } static inline void sbc_synthesize_eight(struct sbc_decoder_state *state, struct sbc_frame *frame, int ch, int blk) { int i, j, k, idx; int *offset = state->offset[ch]; for (i = 0; i < 16; i++) { /* Shifting */ offset[i]--; if (offset[i] < 0) { offset[i] = 159; for (j = 0; j < 9; j++) state->V[ch][j + 160] = state->V[ch][j]; } /* Distribute the new matrix value to the shifted position */ state->V[ch][offset[i]] = SCALE8_STAGED1( MULA(synmatrix8[i][0], frame->sb_sample[blk][ch][0], MULA(synmatrix8[i][1], frame->sb_sample[blk][ch][1], MULA(synmatrix8[i][2], frame->sb_sample[blk][ch][2], MULA(synmatrix8[i][3], frame->sb_sample[blk][ch][3], MULA(synmatrix8[i][4], frame->sb_sample[blk][ch][4], MULA(synmatrix8[i][5], frame->sb_sample[blk][ch][5], MULA(synmatrix8[i][6], frame->sb_sample[blk][ch][6], MUL( synmatrix8[i][7], frame->sb_sample[blk][ch][7]))))))))); } /* Compute the samples */ for (idx = 0, i = 0; i < 8; i++, idx += 5) { k = (i + 8) & 0xf; /* Store in output, Q0 */ frame->pcm_sample[ch][blk * 8 + i] = sbc_clip16(SCALE8_STAGED1( MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0], MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0], MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1], MULA(state->V[ch][offset[k] + 3], sbc_proto_8_80m1[idx + 1], MULA(state->V[ch][offset[i] + 4], sbc_proto_8_80m0[idx + 2], MULA(state->V[ch][offset[k] + 5], sbc_proto_8_80m1[idx + 2], MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3], MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3], MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4], MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4])))))))))))); } } static int sbc_synthesize_audio(struct sbc_decoder_state *state, struct sbc_frame *frame) { int ch, blk; switch (frame->subbands) { case 4: for (ch = 0; ch < frame->channels; ch++) { for (blk = 0; blk < frame->blocks; blk++) sbc_synthesize_four(state, frame, ch, blk); } return frame->blocks * 4; case 8: for (ch = 0; ch < frame->channels; ch++) { for (blk = 0; blk < frame->blocks; blk++) sbc_synthesize_eight(state, frame, ch, blk); } return frame->blocks * 8; default: return -EIO; } } static int sbc_analyze_audio(struct sbc_encoder_state *state, struct sbc_frame *frame) { int ch, blk; int16_t *x; switch (frame->subbands) { case 4: for (ch = 0; ch < frame->channels; ch++) { x = &state->X[ch][state->position - 16 + frame->blocks * 4]; for (blk = 0; blk < frame->blocks; blk += 4) { state->sbc_analyze_4b_4s( x, frame->sb_sample_f[blk][ch], frame->sb_sample_f[blk + 1][ch] - frame->sb_sample_f[blk][ch]); x -= 16; } } return frame->blocks * 4; case 8: for (ch = 0; ch < frame->channels; ch++) { x = &state->X[ch][state->position - 32 + frame->blocks * 8]; for (blk = 0; blk < frame->blocks; blk += 4) { state->sbc_analyze_4b_8s( x, frame->sb_sample_f[blk][ch], frame->sb_sample_f[blk + 1][ch] - frame->sb_sample_f[blk][ch]); x -= 32; } } return frame->blocks * 8; default: return -EIO; } } /* Supplementary bitstream writing macros for 'sbc_pack_frame' */ #define PUT_BITS(data_ptr, bits_cache, bits_count, v, n) \ do { \ bits_cache = (v) | (bits_cache << (n)); \ bits_count += (n); \ if (bits_count >= 16) { \ bits_count -= 8; \ *data_ptr++ = (uint8_t) \ (bits_cache >> bits_count); \ bits_count -= 8; \ *data_ptr++ = (uint8_t) \ (bits_cache >> bits_count); \ } \ } while (0) #define FLUSH_BITS(data_ptr, bits_cache, bits_count) \ do { \ while (bits_count >= 8) { \ bits_count -= 8; \ *data_ptr++ = (uint8_t) \ (bits_cache >> bits_count); \ } \ if (bits_count > 0) \ *data_ptr++ = (uint8_t) \ (bits_cache << (8 - bits_count)); \ } while (0) /* * Packs the SBC frame from frame into the memory at data. At most len * bytes will be used, should more memory be needed an appropriate * error code will be returned. Returns the length of the packed frame * on success or a negative value on error. * * The error codes are: * -1 Not enough memory reserved * -2 Unsupported sampling rate * -3 Unsupported number of blocks * -4 Unsupported number of subbands * -5 Bitpool value out of bounds * -99 not implemented */ static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data, struct sbc_frame *frame, size_t len, int frame_subbands, int frame_channels, int joint) { /* Bitstream writer starts from the fourth byte */ uint8_t *data_ptr = data + 4; uint32_t bits_cache = 0; uint32_t bits_count = 0; /* Will copy the header parts for CRC-8 calculation here */ uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; int crc_pos = 0; uint32_t audio_sample; int ch, sb, blk; /* channel, subband, block and bit counters */ int bits[2][8]; /* bits distribution */ uint32_t levels[2][8]; /* levels are derived from that */ uint32_t sb_sample_delta[2][8]; data[0] = SBC_SYNCWORD; data[1] = (frame->frequency & 0x03) << 6; data[1] |= (frame->block_mode & 0x03) << 4; data[1] |= (frame->mode & 0x03) << 2; data[1] |= (frame->allocation & 0x01) << 1; switch (frame_subbands) { case 4: /* Nothing to do */ break; case 8: data[1] |= 0x01; break; default: return -4; break; } data[2] = frame->bitpool; if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) && frame->bitpool > frame_subbands << 4) return -5; if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) && frame->bitpool > frame_subbands << 5) return -5; /* Can't fill in crc yet */ crc_header[0] = data[1]; crc_header[1] = data[2]; crc_pos = 16; if (frame->mode == JOINT_STEREO) { PUT_BITS(data_ptr, bits_cache, bits_count, joint, frame_subbands); crc_header[crc_pos >> 3] = joint; crc_pos += frame_subbands; } for (ch = 0; ch < frame_channels; ch++) { for (sb = 0; sb < frame_subbands; sb++) { PUT_BITS(data_ptr, bits_cache, bits_count, frame->scale_factor[ch][sb] & 0x0F, 4); crc_header[crc_pos >> 3] <<= 4; crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F; crc_pos += 4; } } /* align the last crc byte */ if (crc_pos % 8) crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8); data[3] = sbc_crc8(crc_header, crc_pos); sbc_calculate_bits(frame, bits); for (ch = 0; ch < frame_channels; ch++) { for (sb = 0; sb < frame_subbands; sb++) { levels[ch][sb] = ((1 << bits[ch][sb]) - 1) << (32 - (frame->scale_factor[ch][sb] + SCALE_OUT_BITS + 2)); sb_sample_delta[ch][sb] = (uint32_t) 1 << (frame->scale_factor[ch][sb] + SCALE_OUT_BITS + 1); } } for (blk = 0; blk < frame->blocks; blk++) { for (ch = 0; ch < frame_channels; ch++) { for (sb = 0; sb < frame_subbands; sb++) { if (bits[ch][sb] == 0) continue; audio_sample = ((uint64_t) levels[ch][sb] * (sb_sample_delta[ch][sb] + frame->sb_sample_f[blk][ch][sb])) >> 32; PUT_BITS(data_ptr, bits_cache, bits_count, audio_sample, bits[ch][sb]); } } } FLUSH_BITS(data_ptr, bits_cache, bits_count); return data_ptr - data; } static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len, int joint) { if (frame->subbands == 4) { if (frame->channels == 1) return sbc_pack_frame_internal( data, frame, len, 4, 1, joint); else return sbc_pack_frame_internal( data, frame, len, 4, 2, joint); } else { if (frame->channels == 1) return sbc_pack_frame_internal( data, frame, len, 8, 1, joint); else return sbc_pack_frame_internal( data, frame, len, 8, 2, joint); } } static void sbc_encoder_init(struct sbc_encoder_state *state, const struct sbc_frame *frame) { memset(&state->X, 0, sizeof(state->X)); state->position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7; sbc_init_primitives(state); } struct sbc_priv { int init; struct SBC_ALIGNED sbc_frame frame; struct SBC_ALIGNED sbc_decoder_state dec_state; struct SBC_ALIGNED sbc_encoder_state enc_state; }; static void sbc_set_defaults(sbc_t *sbc, unsigned long flags) { sbc->frequency = SBC_FREQ_44100; sbc->mode = SBC_MODE_STEREO; sbc->subbands = SBC_SB_8; sbc->blocks = SBC_BLK_16; sbc->bitpool = 32; #if __BYTE_ORDER == __LITTLE_ENDIAN sbc->endian = SBC_LE; #elif __BYTE_ORDER == __BIG_ENDIAN sbc->endian = SBC_BE; #else #error "Unknown byte order" #endif } int sbc_init(sbc_t *sbc, unsigned long flags) { if (!sbc) return -EIO; memset(sbc, 0, sizeof(sbc_t)); sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK); if (!sbc->priv_alloc_base) return -ENOMEM; sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base + SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK)); memset(sbc->priv, 0, sizeof(struct sbc_priv)); sbc_set_defaults(sbc, flags); return 0; } ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len) { return sbc_decode(sbc, input, input_len, NULL, 0, NULL); } ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len, void *output, size_t output_len, size_t *written) { struct sbc_priv *priv; char *ptr; int i, ch, framelen, samples; if (!sbc || !input) return -EIO; priv = sbc->priv; framelen = sbc_unpack_frame(input, &priv->frame, input_len); if (!priv->init) { sbc_decoder_init(&priv->dec_state, &priv->frame); priv->init = 1; sbc->frequency = priv->frame.frequency; sbc->mode = priv->frame.mode; sbc->subbands = priv->frame.subband_mode; sbc->blocks = priv->frame.block_mode; sbc->allocation = priv->frame.allocation; sbc->bitpool = priv->frame.bitpool; priv->frame.codesize = sbc_get_codesize(sbc); priv->frame.length = framelen; } else if (priv->frame.bitpool != sbc->bitpool) { priv->frame.length = framelen; sbc->bitpool = priv->frame.bitpool; } if (!output) return framelen; if (written) *written = 0; if (framelen <= 0) return framelen; samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame); ptr = output; if (output_len < (size_t) (samples * priv->frame.channels * 2)) samples = output_len / (priv->frame.channels * 2); for (i = 0; i < samples; i++) { for (ch = 0; ch < priv->frame.channels; ch++) { int16_t s; s = priv->frame.pcm_sample[ch][i]; if (sbc->endian == SBC_BE) { *ptr++ = (s & 0xff00) >> 8; *ptr++ = (s & 0x00ff); } else { *ptr++ = (s & 0x00ff); *ptr++ = (s & 0xff00) >> 8; } } } if (written) *written = samples * priv->frame.channels * 2; return framelen; } ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len, void *output, size_t output_len, ssize_t *written) { struct sbc_priv *priv; int samples; ssize_t framelen; int (*sbc_enc_process_input)(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels); if (!sbc || !input) return -EIO; priv = sbc->priv; if (written) *written = 0; if (!priv->init) { priv->frame.frequency = sbc->frequency; priv->frame.mode = sbc->mode; priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2; priv->frame.allocation = sbc->allocation; priv->frame.subband_mode = sbc->subbands; priv->frame.subbands = sbc->subbands ? 8 : 4; priv->frame.block_mode = sbc->blocks; priv->frame.blocks = 4 + (sbc->blocks * 4); priv->frame.bitpool = sbc->bitpool; priv->frame.codesize = sbc_get_codesize(sbc); priv->frame.length = sbc_get_frame_length(sbc); sbc_encoder_init(&priv->enc_state, &priv->frame); priv->init = 1; } else if (priv->frame.bitpool != sbc->bitpool) { priv->frame.length = sbc_get_frame_length(sbc); priv->frame.bitpool = sbc->bitpool; } /* input must be large enough to encode a complete frame */ if (input_len < priv->frame.codesize) return 0; /* output must be large enough to receive the encoded frame */ if (!output || output_len < priv->frame.length) return -ENOSPC; /* Select the needed input data processing function and call it */ if (priv->frame.subbands == 8) { if (sbc->endian == SBC_BE) sbc_enc_process_input = priv->enc_state.sbc_enc_process_input_8s_be; else sbc_enc_process_input = priv->enc_state.sbc_enc_process_input_8s_le; } else { if (sbc->endian == SBC_BE) sbc_enc_process_input = priv->enc_state.sbc_enc_process_input_4s_be; else sbc_enc_process_input = priv->enc_state.sbc_enc_process_input_4s_le; } priv->enc_state.position = sbc_enc_process_input( priv->enc_state.position, (const uint8_t *) input, priv->enc_state.X, priv->frame.subbands * priv->frame.blocks, priv->frame.channels); samples = sbc_analyze_audio(&priv->enc_state, &priv->frame); if (priv->frame.mode == JOINT_STEREO) { int j = priv->enc_state.sbc_calc_scalefactors_j( priv->frame.sb_sample_f, priv->frame.scale_factor, priv->frame.blocks, priv->frame.subbands); framelen = sbc_pack_frame(output, &priv->frame, output_len, j); } else { priv->enc_state.sbc_calc_scalefactors( priv->frame.sb_sample_f, priv->frame.scale_factor, priv->frame.blocks, priv->frame.channels, priv->frame.subbands); framelen = sbc_pack_frame(output, &priv->frame, output_len, 0); } if (written) *written = framelen; return samples * priv->frame.channels * 2; } void sbc_finish(sbc_t *sbc) { if (!sbc) return; free(sbc->priv_alloc_base); memset(sbc, 0, sizeof(sbc_t)); } size_t sbc_get_frame_length(sbc_t *sbc) { int ret; uint8_t subbands, channels, blocks, joint, bitpool; struct sbc_priv *priv; priv = sbc->priv; if (priv->init && priv->frame.bitpool == sbc->bitpool) return priv->frame.length; subbands = sbc->subbands ? 8 : 4; blocks = 4 + (sbc->blocks * 4); channels = sbc->mode == SBC_MODE_MONO ? 1 : 2; joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0; bitpool = sbc->bitpool; ret = 4 + (4 * subbands * channels) / 8; /* This term is not always evenly divide so we round it up */ if (channels == 1) ret += ((blocks * channels * bitpool) + 7) / 8; else ret += (((joint ? subbands : 0) + blocks * bitpool) + 7) / 8; return ret; } unsigned sbc_get_frame_duration(sbc_t *sbc) { uint8_t subbands, blocks; uint16_t frequency; struct sbc_priv *priv; priv = sbc->priv; if (!priv->init) { subbands = sbc->subbands ? 8 : 4; blocks = 4 + (sbc->blocks * 4); } else { subbands = priv->frame.subbands; blocks = priv->frame.blocks; } switch (sbc->frequency) { case SBC_FREQ_16000: frequency = 16000; break; case SBC_FREQ_32000: frequency = 32000; break; case SBC_FREQ_44100: frequency = 44100; break; case SBC_FREQ_48000: frequency = 48000; break; default: return 0; } return (1000000 * blocks * subbands) / frequency; } size_t sbc_get_codesize(sbc_t *sbc) { uint16_t subbands, channels, blocks; struct sbc_priv *priv; priv = sbc->priv; if (!priv->init) { subbands = sbc->subbands ? 8 : 4; blocks = 4 + (sbc->blocks * 4); channels = sbc->mode == SBC_MODE_MONO ? 1 : 2; } else { subbands = priv->frame.subbands; blocks = priv->frame.blocks; channels = priv->frame.channels; } return subbands * blocks * channels * 2; } const char *sbc_get_implementation_info(sbc_t *sbc) { struct sbc_priv *priv; if (!sbc) return NULL; priv = sbc->priv; if (!priv) return NULL; return priv->enc_state.implementation_info; } int sbc_reinit(sbc_t *sbc, unsigned long flags) { struct sbc_priv *priv; if (!sbc || !sbc->priv) return -EIO; priv = sbc->priv; if (priv->init == 1) memset(sbc->priv, 0, sizeof(struct sbc_priv)); sbc_set_defaults(sbc, flags); return 0; } bluez-4.101/sbc/sbcdec.c0000644000000000000000000001446111571052274011677 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) decoder * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "sbc.h" #include "formats.h" #define BUF_SIZE 8192 static int verbose = 0; static void decode(char *filename, char *output, int tofile) { unsigned char buf[BUF_SIZE], *stream; struct stat st; sbc_t sbc; int fd, ad, pos, streamlen, framelen, count; size_t len; int format = AFMT_S16_BE, frequency, channels; ssize_t written; if (stat(filename, &st) < 0) { fprintf(stderr, "Can't get size of file %s: %s\n", filename, strerror(errno)); return; } stream = malloc(st.st_size); if (!stream) { fprintf(stderr, "Can't allocate memory for %s: %s\n", filename, strerror(errno)); return; } fd = open(filename, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open file %s: %s\n", filename, strerror(errno)); goto free; } if (read(fd, stream, st.st_size) != st.st_size) { fprintf(stderr, "Can't read content of %s: %s\n", filename, strerror(errno)); close(fd); goto free; } close(fd); pos = 0; streamlen = st.st_size; if (tofile) ad = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644); else ad = open(output, O_WRONLY, 0); if (ad < 0) { fprintf(stderr, "Can't open output %s: %s\n", output, strerror(errno)); goto free; } sbc_init(&sbc, 0L); sbc.endian = SBC_BE; framelen = sbc_decode(&sbc, stream, streamlen, buf, sizeof(buf), &len); channels = sbc.mode == SBC_MODE_MONO ? 1 : 2; switch (sbc.frequency) { case SBC_FREQ_16000: frequency = 16000; break; case SBC_FREQ_32000: frequency = 32000; break; case SBC_FREQ_44100: frequency = 44100; break; case SBC_FREQ_48000: frequency = 48000; break; default: frequency = 0; } if (verbose) { fprintf(stderr,"decoding %s with rate %d, %d subbands, " "%d bits, allocation method %s and mode %s\n", filename, frequency, sbc.subbands * 4 + 4, sbc.bitpool, sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS", sbc.mode == SBC_MODE_MONO ? "MONO" : sbc.mode == SBC_MODE_STEREO ? "STEREO" : "JOINTSTEREO"); } if (tofile) { struct au_header au_hdr; au_hdr.magic = AU_MAGIC; au_hdr.hdr_size = BE_INT(24); au_hdr.data_size = BE_INT(0); au_hdr.encoding = BE_INT(AU_FMT_LIN16); au_hdr.sample_rate = BE_INT(frequency); au_hdr.channels = BE_INT(channels); written = write(ad, &au_hdr, sizeof(au_hdr)); if (written < (ssize_t) sizeof(au_hdr)) { fprintf(stderr, "Failed to write header\n"); goto close; } } else { if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) { fprintf(stderr, "Can't set audio format on %s: %s\n", output, strerror(errno)); goto close; } if (ioctl(ad, SNDCTL_DSP_CHANNELS, &channels) < 0) { fprintf(stderr, "Can't set number of channels on %s: %s\n", output, strerror(errno)); goto close; } if (ioctl(ad, SNDCTL_DSP_SPEED, &frequency) < 0) { fprintf(stderr, "Can't set audio rate on %s: %s\n", output, strerror(errno)); goto close; } } count = len; while (framelen > 0) { /* we have completed an sbc_decode at this point sbc.len is the * length of the frame we just decoded count is the number of * decoded bytes yet to be written */ if (count + len >= BUF_SIZE) { /* buffer is too full to stuff decoded audio in so it * must be written to the device */ written = write(ad, buf, count); if (written > 0) count -= written; } /* sanity check */ if (count + len >= BUF_SIZE) { fprintf(stderr, "buffer size of %d is too small for decoded" " data (%lu)\n", BUF_SIZE, (unsigned long) (len + count)); exit(1); } /* push the pointer in the file forward to the next bit to be * decoded tell the decoder to decode up to the remaining * length of the file (!) */ pos += framelen; framelen = sbc_decode(&sbc, stream + pos, streamlen - pos, buf + count, sizeof(buf) - count, &len); /* increase the count */ count += len; } if (count > 0) { written = write(ad, buf, count); if (written > 0) count -= written; } close: sbc_finish(&sbc); close(ad); free: free(stream); } static void usage(void) { printf("SBC decoder utility ver %s\n", VERSION); printf("Copyright (c) 2004-2010 Marcel Holtmann\n\n"); printf("Usage:\n" "\tsbcdec [options] file(s)\n" "\n"); printf("Options:\n" "\t-h, --help Display help\n" "\t-v, --verbose Verbose mode\n" "\t-d, --device Sound device\n" "\t-f, --file Decode to a file\n" "\n"); } static struct option main_options[] = { { "help", 0, 0, 'h' }, { "device", 1, 0, 'd' }, { "verbose", 0, 0, 'v' }, { "file", 1, 0, 'f' }, { 0, 0, 0, 0 } }; int main(int argc, char *argv[]) { char *output = NULL; int i, opt, tofile = 0; while ((opt = getopt_long(argc, argv, "+hvd:f:", main_options, NULL)) != -1) { switch(opt) { case 'h': usage(); exit(0); case 'v': verbose = 1; break; case 'd': free(output); output = strdup(optarg); tofile = 0; break; case 'f' : free(output); output = strdup(optarg); tofile = 1; break; default: exit(1); } } argc -= optind; argv += optind; optind = 0; if (argc < 1) { usage(); exit(1); } for (i = 0; i < argc; i++) decode(argv[i], output ? output : "/dev/dsp", tofile); free(output); return 0; } bluez-4.101/sbc/sbc_primitives_iwmmxt.c0000644000000000000000000002321111766125764015107 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2010 Keith Mok * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "sbc.h" #include "sbc_math.h" #include "sbc_tables.h" #include "sbc_primitives_iwmmxt.h" /* * IWMMXT optimizations */ #ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT static inline void sbc_analyze_four_iwmmxt(const int16_t *in, int32_t *out, const FIXED_T *consts) { __asm__ volatile ( "wldrd wr0, [%0]\n" "tbcstw wr4, %2\n" "wldrd wr2, [%1]\n" "wldrd wr1, [%0, #8]\n" "wldrd wr3, [%1, #8]\n" "wmadds wr0, wr2, wr0\n" " wldrd wr6, [%0, #16]\n" "wmadds wr1, wr3, wr1\n" " wldrd wr7, [%0, #24]\n" "waddwss wr0, wr0, wr4\n" " wldrd wr8, [%1, #16]\n" "waddwss wr1, wr1, wr4\n" " wldrd wr9, [%1, #24]\n" " wmadds wr6, wr8, wr6\n" " wldrd wr2, [%0, #32]\n" " wmadds wr7, wr9, wr7\n" " wldrd wr3, [%0, #40]\n" " waddwss wr0, wr6, wr0\n" " wldrd wr4, [%1, #32]\n" " waddwss wr1, wr7, wr1\n" " wldrd wr5, [%1, #40]\n" " wmadds wr2, wr4, wr2\n" "wldrd wr6, [%0, #48]\n" " wmadds wr3, wr5, wr3\n" "wldrd wr7, [%0, #56]\n" " waddwss wr0, wr2, wr0\n" "wldrd wr8, [%1, #48]\n" " waddwss wr1, wr3, wr1\n" "wldrd wr9, [%1, #56]\n" "wmadds wr6, wr8, wr6\n" " wldrd wr2, [%0, #64]\n" "wmadds wr7, wr9, wr7\n" " wldrd wr3, [%0, #72]\n" "waddwss wr0, wr6, wr0\n" " wldrd wr4, [%1, #64]\n" "waddwss wr1, wr7, wr1\n" " wldrd wr5, [%1, #72]\n" " wmadds wr2, wr4, wr2\n" "tmcr wcgr0, %4\n" " wmadds wr3, wr5, wr3\n" " waddwss wr0, wr2, wr0\n" " waddwss wr1, wr3, wr1\n" "\n" "wsrawg wr0, wr0, wcgr0\n" " wldrd wr4, [%1, #80]\n" "wsrawg wr1, wr1, wcgr0\n" " wldrd wr5, [%1, #88]\n" "wpackwss wr0, wr0, wr0\n" " wldrd wr6, [%1, #96]\n" "wpackwss wr1, wr1, wr1\n" "wmadds wr2, wr5, wr0\n" " wldrd wr7, [%1, #104]\n" "wmadds wr0, wr4, wr0\n" "\n" " wmadds wr3, wr7, wr1\n" " wmadds wr1, wr6, wr1\n" " waddwss wr2, wr3, wr2\n" " waddwss wr0, wr1, wr0\n" "\n" "wstrd wr0, [%3]\n" "wstrd wr2, [%3, #8]\n" : : "r" (in), "r" (consts), "r" (1 << (SBC_PROTO_FIXED4_SCALE - 1)), "r" (out), "r" (SBC_PROTO_FIXED4_SCALE) : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", "wr8", "wr9", "wcgr0", "memory"); } static inline void sbc_analyze_eight_iwmmxt(const int16_t *in, int32_t *out, const FIXED_T *consts) { __asm__ volatile ( "wldrd wr0, [%0]\n" "tbcstw wr15, %2\n" "wldrd wr1, [%0, #8]\n" "wldrd wr2, [%0, #16]\n" "wldrd wr3, [%0, #24]\n" "wldrd wr4, [%1]\n" "wldrd wr5, [%1, #8]\n" "wldrd wr6, [%1, #16]\n" "wldrd wr7, [%1, #24]\n" "wmadds wr0, wr0, wr4\n" " wldrd wr8, [%1, #32]\n" "wmadds wr1, wr1, wr5\n" " wldrd wr9, [%1, #40]\n" "wmadds wr2, wr2, wr6\n" " wldrd wr10, [%1, #48]\n" "wmadds wr3, wr3, wr7\n" " wldrd wr11, [%1, #56]\n" "waddwss wr0, wr0, wr15\n" " wldrd wr4, [%0, #32]\n" "waddwss wr1, wr1, wr15\n" " wldrd wr5, [%0, #40]\n" "waddwss wr2, wr2, wr15\n" " wldrd wr6, [%0, #48]\n" "waddwss wr3, wr3, wr15\n" " wldrd wr7, [%0, #56]\n" " wmadds wr4, wr4, wr8\n" " wldrd wr12, [%0, #64]\n" " wmadds wr5, wr5, wr9\n" " wldrd wr13, [%0, #72]\n" " wmadds wr6, wr6, wr10\n" " wldrd wr14, [%0, #80]\n" " wmadds wr7, wr7, wr11\n" " wldrd wr15, [%0, #88]\n" " waddwss wr0, wr4, wr0\n" " wldrd wr8, [%1, #64]\n" " waddwss wr1, wr5, wr1\n" " wldrd wr9, [%1, #72]\n" " waddwss wr2, wr6, wr2\n" " wldrd wr10, [%1, #80]\n" " waddwss wr3, wr7, wr3\n" " wldrd wr11, [%1, #88]\n" " wmadds wr12, wr12, wr8\n" "wldrd wr4, [%0, #96]\n" " wmadds wr13, wr13, wr9\n" "wldrd wr5, [%0, #104]\n" " wmadds wr14, wr14, wr10\n" "wldrd wr6, [%0, #112]\n" " wmadds wr15, wr15, wr11\n" "wldrd wr7, [%0, #120]\n" " waddwss wr0, wr12, wr0\n" "wldrd wr8, [%1, #96]\n" " waddwss wr1, wr13, wr1\n" "wldrd wr9, [%1, #104]\n" " waddwss wr2, wr14, wr2\n" "wldrd wr10, [%1, #112]\n" " waddwss wr3, wr15, wr3\n" "wldrd wr11, [%1, #120]\n" "wmadds wr4, wr4, wr8\n" " wldrd wr12, [%0, #128]\n" "wmadds wr5, wr5, wr9\n" " wldrd wr13, [%0, #136]\n" "wmadds wr6, wr6, wr10\n" " wldrd wr14, [%0, #144]\n" "wmadds wr7, wr7, wr11\n" " wldrd wr15, [%0, #152]\n" "waddwss wr0, wr4, wr0\n" " wldrd wr8, [%1, #128]\n" "waddwss wr1, wr5, wr1\n" " wldrd wr9, [%1, #136]\n" "waddwss wr2, wr6, wr2\n" " wldrd wr10, [%1, #144]\n" " waddwss wr3, wr7, wr3\n" " wldrd wr11, [%1, #152]\n" " wmadds wr12, wr12, wr8\n" "tmcr wcgr0, %4\n" " wmadds wr13, wr13, wr9\n" " wmadds wr14, wr14, wr10\n" " wmadds wr15, wr15, wr11\n" " waddwss wr0, wr12, wr0\n" " waddwss wr1, wr13, wr1\n" " waddwss wr2, wr14, wr2\n" " waddwss wr3, wr15, wr3\n" "\n" "wsrawg wr0, wr0, wcgr0\n" "wsrawg wr1, wr1, wcgr0\n" "wsrawg wr2, wr2, wcgr0\n" "wsrawg wr3, wr3, wcgr0\n" "\n" "wpackwss wr0, wr0, wr0\n" "wpackwss wr1, wr1, wr1\n" " wldrd wr4, [%1, #160]\n" "wpackwss wr2, wr2, wr2\n" " wldrd wr5, [%1, #168]\n" "wpackwss wr3, wr3, wr3\n" " wldrd wr6, [%1, #192]\n" " wmadds wr4, wr4, wr0\n" " wldrd wr7, [%1, #200]\n" " wmadds wr5, wr5, wr0\n" " wldrd wr8, [%1, #224]\n" " wmadds wr6, wr6, wr1\n" " wldrd wr9, [%1, #232]\n" " wmadds wr7, wr7, wr1\n" " waddwss wr4, wr6, wr4\n" " waddwss wr5, wr7, wr5\n" " wmadds wr8, wr8, wr2\n" "wldrd wr6, [%1, #256]\n" " wmadds wr9, wr9, wr2\n" "wldrd wr7, [%1, #264]\n" "waddwss wr4, wr8, wr4\n" " waddwss wr5, wr9, wr5\n" "wmadds wr6, wr6, wr3\n" "wmadds wr7, wr7, wr3\n" "waddwss wr4, wr6, wr4\n" "waddwss wr5, wr7, wr5\n" "\n" "wstrd wr4, [%3]\n" "wstrd wr5, [%3, #8]\n" "\n" "wldrd wr6, [%1, #176]\n" "wldrd wr5, [%1, #184]\n" "wmadds wr5, wr5, wr0\n" "wldrd wr8, [%1, #208]\n" "wmadds wr0, wr6, wr0\n" "wldrd wr9, [%1, #216]\n" "wmadds wr9, wr9, wr1\n" "wldrd wr6, [%1, #240]\n" "wmadds wr1, wr8, wr1\n" "wldrd wr7, [%1, #248]\n" "waddwss wr0, wr1, wr0\n" "waddwss wr5, wr9, wr5\n" "wmadds wr7, wr7, wr2\n" "wldrd wr8, [%1, #272]\n" "wmadds wr2, wr6, wr2\n" "wldrd wr9, [%1, #280]\n" "waddwss wr0, wr2, wr0\n" "waddwss wr5, wr7, wr5\n" "wmadds wr9, wr9, wr3\n" "wmadds wr3, wr8, wr3\n" "waddwss wr0, wr3, wr0\n" "waddwss wr5, wr9, wr5\n" "\n" "wstrd wr0, [%3, #16]\n" "wstrd wr5, [%3, #24]\n" : : "r" (in), "r" (consts), "r" (1 << (SBC_PROTO_FIXED8_SCALE - 1)), "r" (out), "r" (SBC_PROTO_FIXED8_SCALE) : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7", "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15", "wcgr0", "memory"); } static inline void sbc_analyze_4b_4s_iwmmxt(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ sbc_analyze_four_iwmmxt(x + 12, out, analysis_consts_fixed4_simd_odd); out += out_stride; sbc_analyze_four_iwmmxt(x + 8, out, analysis_consts_fixed4_simd_even); out += out_stride; sbc_analyze_four_iwmmxt(x + 4, out, analysis_consts_fixed4_simd_odd); out += out_stride; sbc_analyze_four_iwmmxt(x + 0, out, analysis_consts_fixed4_simd_even); } static inline void sbc_analyze_4b_8s_iwmmxt(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ sbc_analyze_eight_iwmmxt(x + 24, out, analysis_consts_fixed8_simd_odd); out += out_stride; sbc_analyze_eight_iwmmxt(x + 16, out, analysis_consts_fixed8_simd_even); out += out_stride; sbc_analyze_eight_iwmmxt(x + 8, out, analysis_consts_fixed8_simd_odd); out += out_stride; sbc_analyze_eight_iwmmxt(x + 0, out, analysis_consts_fixed8_simd_even); } void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *state) { state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_iwmmxt; state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_iwmmxt; state->implementation_info = "IWMMXT"; } #endif bluez-4.101/sbc/sbcinfo.c0000644000000000000000000001515711571052274012102 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #if __BYTE_ORDER == __LITTLE_ENDIAN struct sbc_frame_hdr { uint8_t syncword:8; /* Sync word */ uint8_t subbands:1; /* Subbands */ uint8_t allocation_method:1; /* Allocation method */ uint8_t channel_mode:2; /* Channel mode */ uint8_t blocks:2; /* Blocks */ uint8_t sampling_frequency:2; /* Sampling frequency */ uint8_t bitpool:8; /* Bitpool */ uint8_t crc_check:8; /* CRC check */ } __attribute__ ((packed)); #elif __BYTE_ORDER == __BIG_ENDIAN struct sbc_frame_hdr { uint8_t syncword:8; /* Sync word */ uint8_t sampling_frequency:2; /* Sampling frequency */ uint8_t blocks:2; /* Blocks */ uint8_t channel_mode:2; /* Channel mode */ uint8_t allocation_method:1; /* Allocation method */ uint8_t subbands:1; /* Subbands */ uint8_t bitpool:8; /* Bitpool */ uint8_t crc_check:8; /* CRC check */ } __attribute__ ((packed)); #else #error "Unknown byte order" #endif static int calc_frame_len(struct sbc_frame_hdr *hdr) { int tmp, nrof_subbands, nrof_blocks; nrof_subbands = (hdr->subbands + 1) * 4; nrof_blocks = (hdr->blocks + 1) * 4; switch (hdr->channel_mode) { case 0x00: nrof_subbands /= 2; tmp = nrof_blocks * hdr->bitpool; break; case 0x01: tmp = nrof_blocks * hdr->bitpool * 2; break; case 0x02: tmp = nrof_blocks * hdr->bitpool; break; case 0x03: tmp = nrof_blocks * hdr->bitpool + nrof_subbands; break; default: return 0; } return (nrof_subbands + ((tmp + 7) / 8)); } static double calc_bit_rate(struct sbc_frame_hdr *hdr) { int nrof_subbands, nrof_blocks; double f; nrof_subbands = (hdr->subbands + 1) * 4; nrof_blocks = (hdr->blocks + 1) * 4; switch (hdr->sampling_frequency) { case 0: f = 16; break; case 1: f = 32; break; case 2: f = 44.1; break; case 3: f = 48; break; default: return 0; } return ((8 * (calc_frame_len(hdr) + 4) * f) / (nrof_subbands * nrof_blocks)); } static char *freq2str(uint8_t freq) { switch (freq) { case 0: return "16 kHz"; case 1: return "32 kHz"; case 2: return "44.1 kHz"; case 3: return "48 kHz"; default: return "Unknown"; } } static char *mode2str(uint8_t mode) { switch (mode) { case 0: return "Mono"; case 1: return "Dual Channel"; case 2: return "Stereo"; case 3: return "Joint Stereo"; default: return "Unknown"; } } static ssize_t __read(int fd, void *buf, size_t count) { ssize_t len, pos = 0; while (count > 0) { len = read(fd, buf + pos, count); if (len <= 0) return len; count -= len; pos += len; } return pos; } #define SIZE 32 static int analyze_file(char *filename) { struct sbc_frame_hdr hdr; unsigned char buf[64]; double rate; int bitpool[SIZE], frame_len[SIZE]; int subbands, blocks, freq, method; int n, p1, p2, fd, size, num; ssize_t len; unsigned int count; if (strcmp(filename, "-")) { printf("Filename\t\t%s\n", basename(filename)); fd = open(filename, O_RDONLY); if (fd < 0) { perror("Can't open file"); return -1; } } else fd = fileno(stdin); len = __read(fd, &hdr, sizeof(hdr)); if (len != sizeof(hdr) || hdr.syncword != 0x9c) { fprintf(stderr, "Not a SBC audio file\n"); return -1; } subbands = (hdr.subbands + 1) * 4; blocks = (hdr.blocks + 1) * 4; freq = hdr.sampling_frequency; method = hdr.allocation_method; count = calc_frame_len(&hdr); bitpool[0] = hdr.bitpool; frame_len[0] = count + 4; for (n = 1; n < SIZE; n++) { bitpool[n] = 0; frame_len[n] = 0; } if (lseek(fd, 0, SEEK_SET) < 0) { num = 1; rate = calc_bit_rate(&hdr); while (count) { size = count > sizeof(buf) ? sizeof(buf) : count; len = __read(fd, buf, size); if (len < 0) break; count -= len; } } else { num = 0; rate = 0; } while (1) { len = __read(fd, &hdr, sizeof(hdr)); if (len < 0) { fprintf(stderr, "Unable to read frame header" " (error %d)\n", errno); break; } if (len == 0) break; if ((size_t) len < sizeof(hdr) || hdr.syncword != 0x9c) { fprintf(stderr, "Corrupted SBC stream " "(len %zd syncword 0x%02x)\n", len, hdr.syncword); break; } count = calc_frame_len(&hdr); len = count + 4; p1 = -1; p2 = -1; for (n = 0; n < SIZE; n++) { if (p1 < 0 && (bitpool[n] == 0 || bitpool[n] == hdr.bitpool)) p1 = n; if (p2 < 0 && (frame_len[n] == 0 || frame_len[n] == len)) p2 = n; } if (p1 >= 0) bitpool[p1] = hdr.bitpool; if (p2 >= 0) frame_len[p2] = len; while (count) { size = count > sizeof(buf) ? sizeof(buf) : count; len = __read(fd, buf, size); if (len != size) { fprintf(stderr, "Unable to read frame data " "(error %d)\n", errno); break; } count -= len; } rate += calc_bit_rate(&hdr); num++; } printf("Subbands\t\t%d\n", subbands); printf("Block length\t\t%d\n", blocks); printf("Sampling frequency\t%s\n", freq2str(freq)); printf("Channel mode\t\t%s\n", mode2str(hdr.channel_mode)); printf("Allocation method\t%s\n", method ? "SNR" : "Loudness"); printf("Bitpool\t\t\t%d", bitpool[0]); for (n = 1; n < SIZE; n++) if (bitpool[n] > 0) printf(", %d", bitpool[n]); printf("\n"); printf("Number of frames\t%d\n", num); printf("Frame length\t\t%d", frame_len[0]); for (n = 1; n < SIZE; n++) if (frame_len[n] > 0) printf(", %d", frame_len[n]); printf(" Bytes\n"); if (num > 0) printf("Bit rate\t\t%.3f kbps\n", rate / num); if (fd > fileno(stderr)) close(fd); printf("\n"); return 0; } int main(int argc, char *argv[]) { int i; if (argc < 2) { fprintf(stderr, "Usage: sbcinfo \n"); exit(1); } for (i = 0; i < argc - 1; i++) if (analyze_file(argv[i + 1]) < 0) exit(1); return 0; } bluez-4.101/sbc/sbc_primitives_armv6.c0000644000000000000000000002411411766125764014620 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "sbc.h" #include "sbc_math.h" #include "sbc_tables.h" #include "sbc_primitives_armv6.h" /* * ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline. */ #ifdef SBC_BUILD_WITH_ARMV6_SUPPORT static void __attribute__((naked)) sbc_analyze_four_armv6() { /* r0 = in, r1 = out, r2 = consts */ __asm__ volatile ( "push {r1, r4-r7, lr}\n" "push {r8-r11}\n" "ldrd r4, r5, [r0, #0]\n" "ldrd r6, r7, [r2, #0]\n" "ldrd r8, r9, [r0, #16]\n" "ldrd r10, r11, [r2, #16]\n" "mov r14, #0x8000\n" "smlad r3, r4, r6, r14\n" "smlad r12, r5, r7, r14\n" "ldrd r4, r5, [r0, #32]\n" "ldrd r6, r7, [r2, #32]\n" "smlad r3, r8, r10, r3\n" "smlad r12, r9, r11, r12\n" "ldrd r8, r9, [r0, #48]\n" "ldrd r10, r11, [r2, #48]\n" "smlad r3, r4, r6, r3\n" "smlad r12, r5, r7, r12\n" "ldrd r4, r5, [r0, #64]\n" "ldrd r6, r7, [r2, #64]\n" "smlad r3, r8, r10, r3\n" "smlad r12, r9, r11, r12\n" "ldrd r8, r9, [r0, #8]\n" "ldrd r10, r11, [r2, #8]\n" "smlad r3, r4, r6, r3\n" /* t1[0] is done */ "smlad r12, r5, r7, r12\n" /* t1[1] is done */ "ldrd r4, r5, [r0, #24]\n" "ldrd r6, r7, [r2, #24]\n" "pkhtb r3, r12, r3, asr #16\n" /* combine t1[0] and t1[1] */ "smlad r12, r8, r10, r14\n" "smlad r14, r9, r11, r14\n" "ldrd r8, r9, [r0, #40]\n" "ldrd r10, r11, [r2, #40]\n" "smlad r12, r4, r6, r12\n" "smlad r14, r5, r7, r14\n" "ldrd r4, r5, [r0, #56]\n" "ldrd r6, r7, [r2, #56]\n" "smlad r12, r8, r10, r12\n" "smlad r14, r9, r11, r14\n" "ldrd r8, r9, [r0, #72]\n" "ldrd r10, r11, [r2, #72]\n" "smlad r12, r4, r6, r12\n" "smlad r14, r5, r7, r14\n" "ldrd r4, r5, [r2, #80]\n" /* start loading cos table */ "smlad r12, r8, r10, r12\n" /* t1[2] is done */ "smlad r14, r9, r11, r14\n" /* t1[3] is done */ "ldrd r6, r7, [r2, #88]\n" "ldrd r8, r9, [r2, #96]\n" "ldrd r10, r11, [r2, #104]\n" /* cos table fully loaded */ "pkhtb r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */ "smuad r4, r3, r4\n" "smuad r5, r3, r5\n" "smlad r4, r12, r8, r4\n" "smlad r5, r12, r9, r5\n" "smuad r6, r3, r6\n" "smuad r7, r3, r7\n" "smlad r6, r12, r10, r6\n" "smlad r7, r12, r11, r7\n" "pop {r8-r11}\n" "stmia r1, {r4, r5, r6, r7}\n" "pop {r1, r4-r7, pc}\n" ); } #define sbc_analyze_four(in, out, consts) \ ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \ sbc_analyze_four_armv6)((in), (out), (consts)) static void __attribute__((naked)) sbc_analyze_eight_armv6() { /* r0 = in, r1 = out, r2 = consts */ __asm__ volatile ( "push {r1, r4-r7, lr}\n" "push {r8-r11}\n" "ldrd r4, r5, [r0, #24]\n" "ldrd r6, r7, [r2, #24]\n" "ldrd r8, r9, [r0, #56]\n" "ldrd r10, r11, [r2, #56]\n" "mov r14, #0x8000\n" "smlad r3, r4, r6, r14\n" "smlad r12, r5, r7, r14\n" "ldrd r4, r5, [r0, #88]\n" "ldrd r6, r7, [r2, #88]\n" "smlad r3, r8, r10, r3\n" "smlad r12, r9, r11, r12\n" "ldrd r8, r9, [r0, #120]\n" "ldrd r10, r11, [r2, #120]\n" "smlad r3, r4, r6, r3\n" "smlad r12, r5, r7, r12\n" "ldrd r4, r5, [r0, #152]\n" "ldrd r6, r7, [r2, #152]\n" "smlad r3, r8, r10, r3\n" "smlad r12, r9, r11, r12\n" "ldrd r8, r9, [r0, #16]\n" "ldrd r10, r11, [r2, #16]\n" "smlad r3, r4, r6, r3\n" /* t1[6] is done */ "smlad r12, r5, r7, r12\n" /* t1[7] is done */ "ldrd r4, r5, [r0, #48]\n" "ldrd r6, r7, [r2, #48]\n" "pkhtb r3, r12, r3, asr #16\n" /* combine t1[6] and t1[7] */ "str r3, [sp, #-4]!\n" /* save to stack */ "smlad r3, r8, r10, r14\n" "smlad r12, r9, r11, r14\n" "ldrd r8, r9, [r0, #80]\n" "ldrd r10, r11, [r2, #80]\n" "smlad r3, r4, r6, r3\n" "smlad r12, r5, r7, r12\n" "ldrd r4, r5, [r0, #112]\n" "ldrd r6, r7, [r2, #112]\n" "smlad r3, r8, r10, r3\n" "smlad r12, r9, r11, r12\n" "ldrd r8, r9, [r0, #144]\n" "ldrd r10, r11, [r2, #144]\n" "smlad r3, r4, r6, r3\n" "smlad r12, r5, r7, r12\n" "ldrd r4, r5, [r0, #0]\n" "ldrd r6, r7, [r2, #0]\n" "smlad r3, r8, r10, r3\n" /* t1[4] is done */ "smlad r12, r9, r11, r12\n" /* t1[5] is done */ "ldrd r8, r9, [r0, #32]\n" "ldrd r10, r11, [r2, #32]\n" "pkhtb r3, r12, r3, asr #16\n" /* combine t1[4] and t1[5] */ "str r3, [sp, #-4]!\n" /* save to stack */ "smlad r3, r4, r6, r14\n" "smlad r12, r5, r7, r14\n" "ldrd r4, r5, [r0, #64]\n" "ldrd r6, r7, [r2, #64]\n" "smlad r3, r8, r10, r3\n" "smlad r12, r9, r11, r12\n" "ldrd r8, r9, [r0, #96]\n" "ldrd r10, r11, [r2, #96]\n" "smlad r3, r4, r6, r3\n" "smlad r12, r5, r7, r12\n" "ldrd r4, r5, [r0, #128]\n" "ldrd r6, r7, [r2, #128]\n" "smlad r3, r8, r10, r3\n" "smlad r12, r9, r11, r12\n" "ldrd r8, r9, [r0, #8]\n" "ldrd r10, r11, [r2, #8]\n" "smlad r3, r4, r6, r3\n" /* t1[0] is done */ "smlad r12, r5, r7, r12\n" /* t1[1] is done */ "ldrd r4, r5, [r0, #40]\n" "ldrd r6, r7, [r2, #40]\n" "pkhtb r3, r12, r3, asr #16\n" /* combine t1[0] and t1[1] */ "smlad r12, r8, r10, r14\n" "smlad r14, r9, r11, r14\n" "ldrd r8, r9, [r0, #72]\n" "ldrd r10, r11, [r2, #72]\n" "smlad r12, r4, r6, r12\n" "smlad r14, r5, r7, r14\n" "ldrd r4, r5, [r0, #104]\n" "ldrd r6, r7, [r2, #104]\n" "smlad r12, r8, r10, r12\n" "smlad r14, r9, r11, r14\n" "ldrd r8, r9, [r0, #136]\n" "ldrd r10, r11, [r2, #136]!\n" "smlad r12, r4, r6, r12\n" "smlad r14, r5, r7, r14\n" "ldrd r4, r5, [r2, #(160 - 136 + 0)]\n" "smlad r12, r8, r10, r12\n" /* t1[2] is done */ "smlad r14, r9, r11, r14\n" /* t1[3] is done */ "ldrd r6, r7, [r2, #(160 - 136 + 8)]\n" "smuad r4, r3, r4\n" "smuad r5, r3, r5\n" "pkhtb r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */ /* r3 = t2[0:1] */ /* r12 = t2[2:3] */ "pop {r0, r14}\n" /* t2[4:5], t2[6:7] */ "ldrd r8, r9, [r2, #(160 - 136 + 32)]\n" "smuad r6, r3, r6\n" "smuad r7, r3, r7\n" "ldrd r10, r11, [r2, #(160 - 136 + 40)]\n" "smlad r4, r12, r8, r4\n" "smlad r5, r12, r9, r5\n" "ldrd r8, r9, [r2, #(160 - 136 + 64)]\n" "smlad r6, r12, r10, r6\n" "smlad r7, r12, r11, r7\n" "ldrd r10, r11, [r2, #(160 - 136 + 72)]\n" "smlad r4, r0, r8, r4\n" "smlad r5, r0, r9, r5\n" "ldrd r8, r9, [r2, #(160 - 136 + 96)]\n" "smlad r6, r0, r10, r6\n" "smlad r7, r0, r11, r7\n" "ldrd r10, r11, [r2, #(160 - 136 + 104)]\n" "smlad r4, r14, r8, r4\n" "smlad r5, r14, r9, r5\n" "ldrd r8, r9, [r2, #(160 - 136 + 16 + 0)]\n" "smlad r6, r14, r10, r6\n" "smlad r7, r14, r11, r7\n" "ldrd r10, r11, [r2, #(160 - 136 + 16 + 8)]\n" "stmia r1!, {r4, r5}\n" "smuad r4, r3, r8\n" "smuad r5, r3, r9\n" "ldrd r8, r9, [r2, #(160 - 136 + 16 + 32)]\n" "stmia r1!, {r6, r7}\n" "smuad r6, r3, r10\n" "smuad r7, r3, r11\n" "ldrd r10, r11, [r2, #(160 - 136 + 16 + 40)]\n" "smlad r4, r12, r8, r4\n" "smlad r5, r12, r9, r5\n" "ldrd r8, r9, [r2, #(160 - 136 + 16 + 64)]\n" "smlad r6, r12, r10, r6\n" "smlad r7, r12, r11, r7\n" "ldrd r10, r11, [r2, #(160 - 136 + 16 + 72)]\n" "smlad r4, r0, r8, r4\n" "smlad r5, r0, r9, r5\n" "ldrd r8, r9, [r2, #(160 - 136 + 16 + 96)]\n" "smlad r6, r0, r10, r6\n" "smlad r7, r0, r11, r7\n" "ldrd r10, r11, [r2, #(160 - 136 + 16 + 104)]\n" "smlad r4, r14, r8, r4\n" "smlad r5, r14, r9, r5\n" "smlad r6, r14, r10, r6\n" "smlad r7, r14, r11, r7\n" "pop {r8-r11}\n" "stmia r1!, {r4, r5, r6, r7}\n" "pop {r1, r4-r7, pc}\n" ); } #define sbc_analyze_eight(in, out, consts) \ ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \ sbc_analyze_eight_armv6)((in), (out), (consts)) static void sbc_analyze_4b_4s_armv6(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ sbc_analyze_four(x + 12, out, analysis_consts_fixed4_simd_odd); out += out_stride; sbc_analyze_four(x + 8, out, analysis_consts_fixed4_simd_even); out += out_stride; sbc_analyze_four(x + 4, out, analysis_consts_fixed4_simd_odd); out += out_stride; sbc_analyze_four(x + 0, out, analysis_consts_fixed4_simd_even); } static void sbc_analyze_4b_8s_armv6(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ sbc_analyze_eight(x + 24, out, analysis_consts_fixed8_simd_odd); out += out_stride; sbc_analyze_eight(x + 16, out, analysis_consts_fixed8_simd_even); out += out_stride; sbc_analyze_eight(x + 8, out, analysis_consts_fixed8_simd_odd); out += out_stride; sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even); } void sbc_init_primitives_armv6(struct sbc_encoder_state *state) { state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_armv6; state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_armv6; state->implementation_info = "ARMv6 SIMD"; } #endif bluez-4.101/sbc/sbctester.c0000644000000000000000000002112611571052274012446 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2007-2010 Marcel Holtmann * Copyright (C) 2007-2008 Frederic Dalleau * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #define MAXCHANNELS 2 #define DEFACCURACY 7 static double sampletobits(short sample16, int verbose) { double bits = 0; unsigned short bit; int i; if (verbose) printf("===> sampletobits(%hd, %04hX)\n", sample16, sample16); /* Bit 0 is MSB */ if (sample16 < 0) bits = -1; if (verbose) printf("%d", (sample16 < 0) ? 1 : 0); /* Bit 15 is LSB */ for (i = 1; i < 16; i++) { bit = (unsigned short) sample16; bit >>= 15 - i; bit %= 2; if (verbose) printf("%d", bit); if (bit) bits += (1.0 / pow(2.0, i)); } if (verbose) printf("\n"); return bits; } static int calculate_rms_level(SNDFILE * sndref, SF_INFO * infosref, SNDFILE * sndtst, SF_INFO * infostst, int accuracy, char *csvname) { short refsample[MAXCHANNELS], tstsample[MAXCHANNELS]; double refbits, tstbits; double rms_accu[MAXCHANNELS]; double rms_level[MAXCHANNELS]; double rms_limit = 1.0 / (pow(2.0, accuracy - 1) * pow(12.0, 0.5)); FILE *csv = NULL; int i, j, r1, r2, verdict; if (csvname) csv = fopen(csvname, "wt"); if (csv) { fprintf(csv, "num;"); for (j = 0; j < infostst->channels; j++) fprintf(csv, "ref channel %d;tst channel %d;", j, j); fprintf(csv, "\r\n"); } sf_seek(sndref, 0, SEEK_SET); sf_seek(sndtst, 0, SEEK_SET); memset(rms_accu, 0, sizeof(rms_accu)); memset(rms_level, 0, sizeof(rms_level)); for (i = 0; i < infostst->frames; i++) { if (csv) fprintf(csv, "%d;", i); r1 = sf_read_short(sndref, refsample, infostst->channels); if (r1 != infostst->channels) { printf("Failed to read reference data: %s " "(r1=%d, channels=%d)", sf_strerror(sndref), r1, infostst->channels); if (csv) fclose(csv); return -1; } r2 = sf_read_short(sndtst, tstsample, infostst->channels); if (r2 != infostst->channels) { printf("Failed to read test data: %s " "(r2=%d, channels=%d)\n", sf_strerror(sndtst), r2, infostst->channels); if (csv) fclose(csv); return -1; } for (j = 0; j < infostst->channels; j++) { if (csv) fprintf(csv, "%d;%d;", refsample[j], tstsample[j]); refbits = sampletobits(refsample[j], 0); tstbits = sampletobits(tstsample[j], 0); rms_accu[j] += pow(tstbits - refbits, 2.0); } if (csv) fprintf(csv, "\r\n"); } printf("Limit: %f\n", rms_limit); for (j = 0; j < infostst->channels; j++) { printf("Channel %d\n", j); printf("Accumulated %f\n", rms_accu[j]); rms_accu[j] /= (double) infostst->frames; printf("Accumulated / %f = %f\n", (double) infostst->frames, rms_accu[j]); rms_level[j] = sqrt(rms_accu[j]); printf("Level = %f (%f x %f = %f)\n", rms_level[j], rms_level[j], rms_level[j], rms_level[j] * rms_level[j]); } verdict = 1; for (j = 0; j < infostst->channels; j++) { printf("Channel %d: %f\n", j, rms_level[j]); if (rms_level[j] > rms_limit) verdict = 0; } printf("%s return %d\n", __FUNCTION__, verdict); return verdict; } static int check_absolute_diff(SNDFILE * sndref, SF_INFO * infosref, SNDFILE * sndtst, SF_INFO * infostst, int accuracy) { short refsample[MAXCHANNELS], tstsample[MAXCHANNELS]; short refmax[MAXCHANNELS], tstmax[MAXCHANNELS]; double refbits, tstbits; double rms_absolute = 1.0 / (pow(2, accuracy - 2)); double calc_max[MAXCHANNELS]; int calc_count = 0; short r1, r2; double cur_diff; int i, j, verdict; memset(&refmax, 0, sizeof(refmax)); memset(&tstmax, 0, sizeof(tstmax)); memset(&calc_max, 0, sizeof(calc_max)); memset(&refsample, 0, sizeof(refsample)); memset(&tstsample, 0, sizeof(tstsample)); sf_seek(sndref, 0, SEEK_SET); sf_seek(sndtst, 0, SEEK_SET); verdict = 1; printf("Absolute max: %f\n", rms_absolute); for (i = 0; i < infostst->frames; i++) { r1 = sf_read_short(sndref, refsample, infostst->channels); if (r1 != infostst->channels) { printf("Failed to read reference data: %s " "(r1=%d, channels=%d)", sf_strerror(sndref), r1, infostst->channels); return -1; } r2 = sf_read_short(sndtst, tstsample, infostst->channels); if (r2 != infostst->channels) { printf("Failed to read test data: %s " "(r2=%d, channels=%d)\n", sf_strerror(sndtst), r2, infostst->channels); return -1; } for (j = 0; j < infostst->channels; j++) { refbits = sampletobits(refsample[j], 0); tstbits = sampletobits(tstsample[j], 0); cur_diff = fabs(tstbits - refbits); if (cur_diff > rms_absolute) { calc_count++; /* printf("Channel %d exceeded : fabs(%f - %f) = %f > %f\n", j, tstbits, refbits, cur_diff, rms_absolute); */ verdict = 0; } if (cur_diff > calc_max[j]) { calc_max[j] = cur_diff; refmax[j] = refsample[j]; tstmax[j] = tstsample[j]; } } } for (j = 0; j < infostst->channels; j++) { printf("Calculated max: %f (%hd-%hd=%hd)\n", calc_max[j], tstmax[j], refmax[j], tstmax[j] - refmax[j]); } printf("%s return %d\n", __FUNCTION__, verdict); return verdict; } static void usage(void) { printf("SBC conformance test ver %s\n", VERSION); printf("Copyright (c) 2007-2010 Marcel Holtmann\n"); printf("Copyright (c) 2007-2008 Frederic Dalleau\n\n"); printf("Usage:\n" "\tsbctester reference.wav checkfile.wav\n" "\tsbctester integer\n" "\n"); printf("To test the encoder:\n"); printf("\tUse a reference codec to encode original.wav to reference.sbc\n"); printf("\tUse sbcenc to encode original.wav to checkfile.sbc\n"); printf("\tDecode both file using the reference decoder\n"); printf("\tRun sbctester with these two wav files to get the result\n\n"); printf("\tA file called out.csv is generated to use the data in a\n"); printf("\tspreadsheet application or database.\n\n"); } int main(int argc, char *argv[]) { SNDFILE *sndref = NULL; SNDFILE *sndtst = NULL; SF_INFO infosref; SF_INFO infostst; char *ref; char *tst; int pass_rms, pass_absolute, pass, accuracy; if (argc == 2) { double db; printf("Test sampletobits\n"); db = sampletobits((short) atoi(argv[1]), 1); printf("db = %f\n", db); exit(0); } if (argc < 3) { usage(); exit(1); } ref = argv[1]; tst = argv[2]; printf("opening reference %s\n", ref); sndref = sf_open(ref, SFM_READ, &infosref); if (!sndref) { printf("Failed to open reference file\n"); exit(1); } printf("opening testfile %s\n", tst); sndtst = sf_open(tst, SFM_READ, &infostst); if (!sndtst) { printf("Failed to open test file\n"); sf_close(sndref); exit(1); } printf("reference:\n\t%d frames,\n\t%d hz,\n\t%d channels\n", (int) infosref.frames, (int) infosref.samplerate, (int) infosref.channels); printf("testfile:\n\t%d frames,\n\t%d hz,\n\t%d channels\n", (int) infostst.frames, (int) infostst.samplerate, (int) infostst.channels); /* check number of channels */ if (infosref.channels > 2 || infostst.channels > 2) { printf("Too many channels\n"); goto error; } /* compare number of samples */ if (infosref.samplerate != infostst.samplerate || infosref.channels != infostst.channels) { printf("Cannot compare files with different charasteristics\n"); goto error; } accuracy = DEFACCURACY; printf("Accuracy: %d\n", accuracy); /* Condition 1 rms level */ pass_rms = calculate_rms_level(sndref, &infosref, sndtst, &infostst, accuracy, "out.csv"); if (pass_rms < 0) goto error; /* Condition 2 absolute difference */ pass_absolute = check_absolute_diff(sndref, &infosref, sndtst, &infostst, accuracy); if (pass_absolute < 0) goto error; /* Verdict */ pass = pass_rms && pass_absolute; printf("Verdict: %s\n", pass ? "pass" : "fail"); return 0; error: sf_close(sndref); sf_close(sndtst); exit(1); } bluez-4.101/sbc/sbc_primitives_neon.c0000644000000000000000000006641011766125764014531 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include "sbc.h" #include "sbc_math.h" #include "sbc_tables.h" #include "sbc_primitives_neon.h" /* * ARM NEON optimizations */ #ifdef SBC_BUILD_WITH_NEON_SUPPORT static inline void _sbc_analyze_four_neon(const int16_t *in, int32_t *out, const FIXED_T *consts) { /* TODO: merge even and odd cases (or even merge all four calls to this * function) in order to have only aligned reads from 'in' array * and reduce number of load instructions */ __asm__ volatile ( "vld1.16 {d4, d5}, [%0, :64]!\n" "vld1.16 {d8, d9}, [%1, :128]!\n" "vmull.s16 q0, d4, d8\n" "vld1.16 {d6, d7}, [%0, :64]!\n" "vmull.s16 q1, d5, d9\n" "vld1.16 {d10, d11}, [%1, :128]!\n" "vmlal.s16 q0, d6, d10\n" "vld1.16 {d4, d5}, [%0, :64]!\n" "vmlal.s16 q1, d7, d11\n" "vld1.16 {d8, d9}, [%1, :128]!\n" "vmlal.s16 q0, d4, d8\n" "vld1.16 {d6, d7}, [%0, :64]!\n" "vmlal.s16 q1, d5, d9\n" "vld1.16 {d10, d11}, [%1, :128]!\n" "vmlal.s16 q0, d6, d10\n" "vld1.16 {d4, d5}, [%0, :64]!\n" "vmlal.s16 q1, d7, d11\n" "vld1.16 {d8, d9}, [%1, :128]!\n" "vmlal.s16 q0, d4, d8\n" "vmlal.s16 q1, d5, d9\n" "vpadd.s32 d0, d0, d1\n" "vpadd.s32 d1, d2, d3\n" "vrshrn.s32 d0, q0, %3\n" "vld1.16 {d2, d3, d4, d5}, [%1, :128]!\n" "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */ "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */ "vmull.s16 q3, d2, d0\n" "vmull.s16 q4, d3, d0\n" "vmlal.s16 q3, d4, d1\n" "vmlal.s16 q4, d5, d1\n" "vpadd.s32 d0, d6, d7\n" /* TODO: can be eliminated */ "vpadd.s32 d1, d8, d9\n" /* TODO: can be eliminated */ "vst1.32 {d0, d1}, [%2, :128]\n" : "+r" (in), "+r" (consts) : "r" (out), "i" (SBC_PROTO_FIXED4_SCALE) : "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11"); } static inline void _sbc_analyze_eight_neon(const int16_t *in, int32_t *out, const FIXED_T *consts) { /* TODO: merge even and odd cases (or even merge all four calls to this * function) in order to have only aligned reads from 'in' array * and reduce number of load instructions */ __asm__ volatile ( "vld1.16 {d4, d5}, [%0, :64]!\n" "vld1.16 {d8, d9}, [%1, :128]!\n" "vmull.s16 q6, d4, d8\n" "vld1.16 {d6, d7}, [%0, :64]!\n" "vmull.s16 q7, d5, d9\n" "vld1.16 {d10, d11}, [%1, :128]!\n" "vmull.s16 q8, d6, d10\n" "vld1.16 {d4, d5}, [%0, :64]!\n" "vmull.s16 q9, d7, d11\n" "vld1.16 {d8, d9}, [%1, :128]!\n" "vmlal.s16 q6, d4, d8\n" "vld1.16 {d6, d7}, [%0, :64]!\n" "vmlal.s16 q7, d5, d9\n" "vld1.16 {d10, d11}, [%1, :128]!\n" "vmlal.s16 q8, d6, d10\n" "vld1.16 {d4, d5}, [%0, :64]!\n" "vmlal.s16 q9, d7, d11\n" "vld1.16 {d8, d9}, [%1, :128]!\n" "vmlal.s16 q6, d4, d8\n" "vld1.16 {d6, d7}, [%0, :64]!\n" "vmlal.s16 q7, d5, d9\n" "vld1.16 {d10, d11}, [%1, :128]!\n" "vmlal.s16 q8, d6, d10\n" "vld1.16 {d4, d5}, [%0, :64]!\n" "vmlal.s16 q9, d7, d11\n" "vld1.16 {d8, d9}, [%1, :128]!\n" "vmlal.s16 q6, d4, d8\n" "vld1.16 {d6, d7}, [%0, :64]!\n" "vmlal.s16 q7, d5, d9\n" "vld1.16 {d10, d11}, [%1, :128]!\n" "vmlal.s16 q8, d6, d10\n" "vld1.16 {d4, d5}, [%0, :64]!\n" "vmlal.s16 q9, d7, d11\n" "vld1.16 {d8, d9}, [%1, :128]!\n" "vmlal.s16 q6, d4, d8\n" "vld1.16 {d6, d7}, [%0, :64]!\n" "vmlal.s16 q7, d5, d9\n" "vld1.16 {d10, d11}, [%1, :128]!\n" "vmlal.s16 q8, d6, d10\n" "vmlal.s16 q9, d7, d11\n" "vpadd.s32 d0, d12, d13\n" "vpadd.s32 d1, d14, d15\n" "vpadd.s32 d2, d16, d17\n" "vpadd.s32 d3, d18, d19\n" "vrshr.s32 q0, q0, %3\n" "vrshr.s32 q1, q1, %3\n" "vmovn.s32 d0, q0\n" "vmovn.s32 d1, q1\n" "vdup.i32 d3, d1[1]\n" /* TODO: can be eliminated */ "vdup.i32 d2, d1[0]\n" /* TODO: can be eliminated */ "vdup.i32 d1, d0[1]\n" /* TODO: can be eliminated */ "vdup.i32 d0, d0[0]\n" /* TODO: can be eliminated */ "vld1.16 {d4, d5}, [%1, :128]!\n" "vmull.s16 q6, d4, d0\n" "vld1.16 {d6, d7}, [%1, :128]!\n" "vmull.s16 q7, d5, d0\n" "vmull.s16 q8, d6, d0\n" "vmull.s16 q9, d7, d0\n" "vld1.16 {d4, d5}, [%1, :128]!\n" "vmlal.s16 q6, d4, d1\n" "vld1.16 {d6, d7}, [%1, :128]!\n" "vmlal.s16 q7, d5, d1\n" "vmlal.s16 q8, d6, d1\n" "vmlal.s16 q9, d7, d1\n" "vld1.16 {d4, d5}, [%1, :128]!\n" "vmlal.s16 q6, d4, d2\n" "vld1.16 {d6, d7}, [%1, :128]!\n" "vmlal.s16 q7, d5, d2\n" "vmlal.s16 q8, d6, d2\n" "vmlal.s16 q9, d7, d2\n" "vld1.16 {d4, d5}, [%1, :128]!\n" "vmlal.s16 q6, d4, d3\n" "vld1.16 {d6, d7}, [%1, :128]!\n" "vmlal.s16 q7, d5, d3\n" "vmlal.s16 q8, d6, d3\n" "vmlal.s16 q9, d7, d3\n" "vpadd.s32 d0, d12, d13\n" /* TODO: can be eliminated */ "vpadd.s32 d1, d14, d15\n" /* TODO: can be eliminated */ "vpadd.s32 d2, d16, d17\n" /* TODO: can be eliminated */ "vpadd.s32 d3, d18, d19\n" /* TODO: can be eliminated */ "vst1.32 {d0, d1, d2, d3}, [%2, :128]\n" : "+r" (in), "+r" (consts) : "r" (out), "i" (SBC_PROTO_FIXED8_SCALE) : "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", "d16", "d17", "d18", "d19"); } static inline void sbc_analyze_4b_4s_neon(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ _sbc_analyze_four_neon(x + 12, out, analysis_consts_fixed4_simd_odd); out += out_stride; _sbc_analyze_four_neon(x + 8, out, analysis_consts_fixed4_simd_even); out += out_stride; _sbc_analyze_four_neon(x + 4, out, analysis_consts_fixed4_simd_odd); out += out_stride; _sbc_analyze_four_neon(x + 0, out, analysis_consts_fixed4_simd_even); } static inline void sbc_analyze_4b_8s_neon(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ _sbc_analyze_eight_neon(x + 24, out, analysis_consts_fixed8_simd_odd); out += out_stride; _sbc_analyze_eight_neon(x + 16, out, analysis_consts_fixed8_simd_even); out += out_stride; _sbc_analyze_eight_neon(x + 8, out, analysis_consts_fixed8_simd_odd); out += out_stride; _sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even); } static void sbc_calc_scalefactors_neon( int32_t sb_sample_f[16][2][8], uint32_t scale_factor[2][8], int blocks, int channels, int subbands) { int ch, sb; for (ch = 0; ch < channels; ch++) { for (sb = 0; sb < subbands; sb += 4) { int blk = blocks; int32_t *in = &sb_sample_f[0][ch][sb]; __asm__ volatile ( "vmov.s32 q0, #0\n" "vmov.s32 q1, %[c1]\n" "vmov.s32 q14, #1\n" "vmov.s32 q15, %[c2]\n" "vadd.s32 q1, q1, q14\n" "1:\n" "vld1.32 {d16, d17}, [%[in], :128], %[inc]\n" "vabs.s32 q8, q8\n" "vld1.32 {d18, d19}, [%[in], :128], %[inc]\n" "vabs.s32 q9, q9\n" "vld1.32 {d20, d21}, [%[in], :128], %[inc]\n" "vabs.s32 q10, q10\n" "vld1.32 {d22, d23}, [%[in], :128], %[inc]\n" "vabs.s32 q11, q11\n" "vmax.s32 q0, q0, q8\n" "vmax.s32 q1, q1, q9\n" "vmax.s32 q0, q0, q10\n" "vmax.s32 q1, q1, q11\n" "subs %[blk], %[blk], #4\n" "bgt 1b\n" "vmax.s32 q0, q0, q1\n" "vsub.s32 q0, q0, q14\n" "vclz.s32 q0, q0\n" "vsub.s32 q0, q15, q0\n" "vst1.32 {d0, d1}, [%[out], :128]\n" : [blk] "+r" (blk), [in] "+r" (in) : [inc] "r" ((char *) &sb_sample_f[1][0][0] - (char *) &sb_sample_f[0][0][0]), [out] "r" (&scale_factor[ch][sb]), [c1] "i" (1 << SCALE_OUT_BITS), [c2] "i" (31 - SCALE_OUT_BITS) : "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", "cc", "memory"); } } } int sbc_calc_scalefactors_j_neon( int32_t sb_sample_f[16][2][8], uint32_t scale_factor[2][8], int blocks, int subbands) { static SBC_ALIGNED int32_t joint_bits_mask[8] = { 8, 4, 2, 1, 128, 64, 32, 16 }; int joint, i; int32_t *in0, *in1; int32_t *in = &sb_sample_f[0][0][0]; uint32_t *out0, *out1; uint32_t *out = &scale_factor[0][0]; int32_t *consts = joint_bits_mask; i = subbands; __asm__ volatile ( /* * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1 * input: q0 = ((1 << SCALE_OUT_BITS) + 1) * %[in0] - samples for channel 0 * %[in1] - samples for shannel 1 * output: q0, q1 - scale factors without joint stereo * q2, q3 - scale factors with joint stereo * q15 - joint stereo selection mask */ ".macro calc_scalefactors\n" "vmov.s32 q1, q0\n" "vmov.s32 q2, q0\n" "vmov.s32 q3, q0\n" "mov %[i], %[blocks]\n" "1:\n" "vld1.32 {d18, d19}, [%[in1], :128], %[inc]\n" "vbic.s32 q11, q9, q14\n" "vld1.32 {d16, d17}, [%[in0], :128], %[inc]\n" "vhadd.s32 q10, q8, q11\n" "vhsub.s32 q11, q8, q11\n" "vabs.s32 q8, q8\n" "vabs.s32 q9, q9\n" "vabs.s32 q10, q10\n" "vabs.s32 q11, q11\n" "vmax.s32 q0, q0, q8\n" "vmax.s32 q1, q1, q9\n" "vmax.s32 q2, q2, q10\n" "vmax.s32 q3, q3, q11\n" "subs %[i], %[i], #1\n" "bgt 1b\n" "vsub.s32 q0, q0, q14\n" "vsub.s32 q1, q1, q14\n" "vsub.s32 q2, q2, q14\n" "vsub.s32 q3, q3, q14\n" "vclz.s32 q0, q0\n" "vclz.s32 q1, q1\n" "vclz.s32 q2, q2\n" "vclz.s32 q3, q3\n" "vsub.s32 q0, q13, q0\n" "vsub.s32 q1, q13, q1\n" "vsub.s32 q2, q13, q2\n" "vsub.s32 q3, q13, q3\n" ".endm\n" /* * constants: q14 = 1 * input: q15 - joint stereo selection mask * %[in0] - value set by calc_scalefactors macro * %[in1] - value set by calc_scalefactors macro */ ".macro update_joint_stereo_samples\n" "sub %[out1], %[in1], %[inc]\n" "sub %[out0], %[in0], %[inc]\n" "sub %[in1], %[in1], %[inc], asl #1\n" "sub %[in0], %[in0], %[inc], asl #1\n" "vld1.32 {d18, d19}, [%[in1], :128]\n" "vbic.s32 q11, q9, q14\n" "vld1.32 {d16, d17}, [%[in0], :128]\n" "vld1.32 {d2, d3}, [%[out1], :128]\n" "vbic.s32 q3, q1, q14\n" "vld1.32 {d0, d1}, [%[out0], :128]\n" "vhsub.s32 q10, q8, q11\n" "vhadd.s32 q11, q8, q11\n" "vhsub.s32 q2, q0, q3\n" "vhadd.s32 q3, q0, q3\n" "vbif.s32 q10, q9, q15\n" "vbif.s32 d22, d16, d30\n" "sub %[inc], %[zero], %[inc], asl #1\n" "sub %[i], %[blocks], #2\n" "2:\n" "vbif.s32 d23, d17, d31\n" "vst1.32 {d20, d21}, [%[in1], :128], %[inc]\n" "vbif.s32 d4, d2, d30\n" "vld1.32 {d18, d19}, [%[in1], :128]\n" "vbif.s32 d5, d3, d31\n" "vst1.32 {d22, d23}, [%[in0], :128], %[inc]\n" "vbif.s32 d6, d0, d30\n" "vld1.32 {d16, d17}, [%[in0], :128]\n" "vbif.s32 d7, d1, d31\n" "vst1.32 {d4, d5}, [%[out1], :128], %[inc]\n" "vbic.s32 q11, q9, q14\n" "vld1.32 {d2, d3}, [%[out1], :128]\n" "vst1.32 {d6, d7}, [%[out0], :128], %[inc]\n" "vbic.s32 q3, q1, q14\n" "vld1.32 {d0, d1}, [%[out0], :128]\n" "vhsub.s32 q10, q8, q11\n" "vhadd.s32 q11, q8, q11\n" "vhsub.s32 q2, q0, q3\n" "vhadd.s32 q3, q0, q3\n" "vbif.s32 q10, q9, q15\n" "vbif.s32 d22, d16, d30\n" "subs %[i], %[i], #2\n" "bgt 2b\n" "sub %[inc], %[zero], %[inc], asr #1\n" "vbif.s32 d23, d17, d31\n" "vst1.32 {d20, d21}, [%[in1], :128]\n" "vbif.s32 q2, q1, q15\n" "vst1.32 {d22, d23}, [%[in0], :128]\n" "vbif.s32 q3, q0, q15\n" "vst1.32 {d4, d5}, [%[out1], :128]\n" "vst1.32 {d6, d7}, [%[out0], :128]\n" ".endm\n" "vmov.s32 q14, #1\n" "vmov.s32 q13, %[c2]\n" "cmp %[i], #4\n" "bne 8f\n" "4:\n" /* 4 subbands */ "add %[in0], %[in], #0\n" "add %[in1], %[in], #32\n" "add %[out0], %[out], #0\n" "add %[out1], %[out], #32\n" "vmov.s32 q0, %[c1]\n" "vadd.s32 q0, q0, q14\n" "calc_scalefactors\n" /* check whether to use joint stereo for subbands 0, 1, 2 */ "vadd.s32 q15, q0, q1\n" "vadd.s32 q9, q2, q3\n" "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */ "vld1.32 {d16, d17}, [%[consts], :128]!\n" "vcgt.s32 q15, q15, q9\n" /* calculate and save to memory 'joint' variable */ /* update and save scale factors to memory */ " vand.s32 q8, q8, q15\n" "vbit.s32 q0, q2, q15\n" " vpadd.s32 d16, d16, d17\n" "vbit.s32 q1, q3, q15\n" " vpadd.s32 d16, d16, d16\n" "vst1.32 {d0, d1}, [%[out0], :128]\n" "vst1.32 {d2, d3}, [%[out1], :128]\n" " vst1.32 {d16[0]}, [%[joint]]\n" "update_joint_stereo_samples\n" "b 9f\n" "8:\n" /* 8 subbands */ "add %[in0], %[in], #16\n\n" "add %[in1], %[in], #48\n" "add %[out0], %[out], #16\n\n" "add %[out1], %[out], #48\n" "vmov.s32 q0, %[c1]\n" "vadd.s32 q0, q0, q14\n" "calc_scalefactors\n" /* check whether to use joint stereo for subbands 4, 5, 6 */ "vadd.s32 q15, q0, q1\n" "vadd.s32 q9, q2, q3\n" "vmov.s32 d31[1], %[zero]\n" /* last subband -> no joint */ "vld1.32 {d16, d17}, [%[consts], :128]!\n" "vcgt.s32 q15, q15, q9\n" /* calculate part of 'joint' variable and save it to d24 */ /* update and save scale factors to memory */ " vand.s32 q8, q8, q15\n" "vbit.s32 q0, q2, q15\n" " vpadd.s32 d16, d16, d17\n" "vbit.s32 q1, q3, q15\n" "vst1.32 {d0, d1}, [%[out0], :128]\n" "vst1.32 {d2, d3}, [%[out1], :128]\n" " vpadd.s32 d24, d16, d16\n" "update_joint_stereo_samples\n" "add %[in0], %[in], #0\n" "add %[in1], %[in], #32\n" "add %[out0], %[out], #0\n\n" "add %[out1], %[out], #32\n" "vmov.s32 q0, %[c1]\n" "vadd.s32 q0, q0, q14\n" "calc_scalefactors\n" /* check whether to use joint stereo for subbands 0, 1, 2, 3 */ "vadd.s32 q15, q0, q1\n" "vadd.s32 q9, q2, q3\n" "vld1.32 {d16, d17}, [%[consts], :128]!\n" "vcgt.s32 q15, q15, q9\n" /* combine last part of 'joint' with d24 and save to memory */ /* update and save scale factors to memory */ " vand.s32 q8, q8, q15\n" "vbit.s32 q0, q2, q15\n" " vpadd.s32 d16, d16, d17\n" "vbit.s32 q1, q3, q15\n" " vpadd.s32 d16, d16, d16\n" "vst1.32 {d0, d1}, [%[out0], :128]\n" " vadd.s32 d16, d16, d24\n" "vst1.32 {d2, d3}, [%[out1], :128]\n" " vst1.32 {d16[0]}, [%[joint]]\n" "update_joint_stereo_samples\n" "9:\n" ".purgem calc_scalefactors\n" ".purgem update_joint_stereo_samples\n" : [i] "+&r" (i), [in] "+&r" (in), [in0] "=&r" (in0), [in1] "=&r" (in1), [out] "+&r" (out), [out0] "=&r" (out0), [out1] "=&r" (out1), [consts] "+&r" (consts) : [inc] "r" ((char *) &sb_sample_f[1][0][0] - (char *) &sb_sample_f[0][0][0]), [blocks] "r" (blocks), [joint] "r" (&joint), [c1] "i" (1 << SCALE_OUT_BITS), [c2] "i" (31 - SCALE_OUT_BITS), [zero] "r" (0) : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", "cc", "memory"); return joint; } #define PERM_BE(a, b, c, d) { \ (a * 2) + 1, (a * 2) + 0, \ (b * 2) + 1, (b * 2) + 0, \ (c * 2) + 1, (c * 2) + 0, \ (d * 2) + 1, (d * 2) + 0 \ } #define PERM_LE(a, b, c, d) { \ (a * 2) + 0, (a * 2) + 1, \ (b * 2) + 0, (b * 2) + 1, \ (c * 2) + 0, (c * 2) + 1, \ (d * 2) + 0, (d * 2) + 1 \ } static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal( int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels, int big_endian) { static SBC_ALIGNED uint8_t perm_be[2][8] = { PERM_BE(7, 3, 6, 4), PERM_BE(0, 2, 1, 5) }; static SBC_ALIGNED uint8_t perm_le[2][8] = { PERM_LE(7, 3, 6, 4), PERM_LE(0, 2, 1, 5) }; /* handle X buffer wraparound */ if (position < nsamples) { int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40]; int16_t *src = &X[0][position]; __asm__ volatile ( "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0}, [%[src], :64]!\n" "vst1.16 {d0}, [%[dst], :64]!\n" : [dst] "+r" (dst), [src] "+r" (src) : : "memory", "d0", "d1", "d2", "d3"); if (nchannels > 1) { dst = &X[1][SBC_X_BUFFER_SIZE - 40]; src = &X[1][position]; __asm__ volatile ( "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0}, [%[src], :64]!\n" "vst1.16 {d0}, [%[dst], :64]!\n" : [dst] "+r" (dst), [src] "+r" (src) : : "memory", "d0", "d1", "d2", "d3"); } position = SBC_X_BUFFER_SIZE - 40; } if ((nchannels > 1) && ((uintptr_t)pcm & 1)) { /* poor 'pcm' alignment */ int16_t *x = &X[0][position]; int16_t *y = &X[1][position]; __asm__ volatile ( "vld1.8 {d0, d1}, [%[perm], :128]\n" "1:\n" "sub %[x], %[x], #16\n" "sub %[y], %[y], #16\n" "sub %[position], %[position], #8\n" "vld1.8 {d4, d5}, [%[pcm]]!\n" "vuzp.16 d4, d5\n" "vld1.8 {d20, d21}, [%[pcm]]!\n" "vuzp.16 d20, d21\n" "vswp d5, d20\n" "vtbl.8 d16, {d4, d5}, d0\n" "vtbl.8 d17, {d4, d5}, d1\n" "vtbl.8 d18, {d20, d21}, d0\n" "vtbl.8 d19, {d20, d21}, d1\n" "vst1.16 {d16, d17}, [%[x], :128]\n" "vst1.16 {d18, d19}, [%[y], :128]\n" "subs %[nsamples], %[nsamples], #8\n" "bgt 1b\n" : [x] "+r" (x), [y] "+r" (y), [pcm] "+r" (pcm), [nsamples] "+r" (nsamples), [position] "+r" (position) : [perm] "r" (big_endian ? perm_be : perm_le) : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23"); } else if (nchannels > 1) { /* proper 'pcm' alignment */ int16_t *x = &X[0][position]; int16_t *y = &X[1][position]; __asm__ volatile ( "vld1.8 {d0, d1}, [%[perm], :128]\n" "1:\n" "sub %[x], %[x], #16\n" "sub %[y], %[y], #16\n" "sub %[position], %[position], #8\n" "vld2.16 {d4, d5}, [%[pcm]]!\n" "vld2.16 {d20, d21}, [%[pcm]]!\n" "vswp d5, d20\n" "vtbl.8 d16, {d4, d5}, d0\n" "vtbl.8 d17, {d4, d5}, d1\n" "vtbl.8 d18, {d20, d21}, d0\n" "vtbl.8 d19, {d20, d21}, d1\n" "vst1.16 {d16, d17}, [%[x], :128]\n" "vst1.16 {d18, d19}, [%[y], :128]\n" "subs %[nsamples], %[nsamples], #8\n" "bgt 1b\n" : [x] "+r" (x), [y] "+r" (y), [pcm] "+r" (pcm), [nsamples] "+r" (nsamples), [position] "+r" (position) : [perm] "r" (big_endian ? perm_be : perm_le) : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23"); } else { int16_t *x = &X[0][position]; __asm__ volatile ( "vld1.8 {d0, d1}, [%[perm], :128]\n" "1:\n" "sub %[x], %[x], #16\n" "sub %[position], %[position], #8\n" "vld1.8 {d4, d5}, [%[pcm]]!\n" "vtbl.8 d16, {d4, d5}, d0\n" "vtbl.8 d17, {d4, d5}, d1\n" "vst1.16 {d16, d17}, [%[x], :128]\n" "subs %[nsamples], %[nsamples], #8\n" "bgt 1b\n" : [x] "+r" (x), [pcm] "+r" (pcm), [nsamples] "+r" (nsamples), [position] "+r" (position) : [perm] "r" (big_endian ? perm_be : perm_le) : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19"); } return position; } static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal( int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels, int big_endian) { static SBC_ALIGNED uint8_t perm_be[4][8] = { PERM_BE(15, 7, 14, 8), PERM_BE(13, 9, 12, 10), PERM_BE(11, 3, 6, 0), PERM_BE(5, 1, 4, 2) }; static SBC_ALIGNED uint8_t perm_le[4][8] = { PERM_LE(15, 7, 14, 8), PERM_LE(13, 9, 12, 10), PERM_LE(11, 3, 6, 0), PERM_LE(5, 1, 4, 2) }; /* handle X buffer wraparound */ if (position < nsamples) { int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72]; int16_t *src = &X[0][position]; __asm__ volatile ( "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1}, [%[src], :128]!\n" "vst1.16 {d0, d1}, [%[dst], :128]!\n" : [dst] "+r" (dst), [src] "+r" (src) : : "memory", "d0", "d1", "d2", "d3"); if (nchannels > 1) { dst = &X[1][SBC_X_BUFFER_SIZE - 72]; src = &X[1][position]; __asm__ volatile ( "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n" "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n" "vld1.16 {d0, d1}, [%[src], :128]!\n" "vst1.16 {d0, d1}, [%[dst], :128]!\n" : [dst] "+r" (dst), [src] "+r" (src) : : "memory", "d0", "d1", "d2", "d3"); } position = SBC_X_BUFFER_SIZE - 72; } if ((nchannels > 1) && ((uintptr_t)pcm & 1)) { /* poor 'pcm' alignment */ int16_t *x = &X[0][position]; int16_t *y = &X[1][position]; __asm__ volatile ( "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n" "1:\n" "sub %[x], %[x], #32\n" "sub %[y], %[y], #32\n" "sub %[position], %[position], #16\n" "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n" "vuzp.16 q2, q3\n" "vld1.8 {d20, d21, d22, d23}, [%[pcm]]!\n" "vuzp.16 q10, q11\n" "vswp q3, q10\n" "vtbl.8 d16, {d4, d5, d6, d7}, d0\n" "vtbl.8 d17, {d4, d5, d6, d7}, d1\n" "vtbl.8 d18, {d4, d5, d6, d7}, d2\n" "vtbl.8 d19, {d4, d5, d6, d7}, d3\n" "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n" "vtbl.8 d16, {d20, d21, d22, d23}, d0\n" "vtbl.8 d17, {d20, d21, d22, d23}, d1\n" "vtbl.8 d18, {d20, d21, d22, d23}, d2\n" "vtbl.8 d19, {d20, d21, d22, d23}, d3\n" "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n" "subs %[nsamples], %[nsamples], #16\n" "bgt 1b\n" : [x] "+r" (x), [y] "+r" (y), [pcm] "+r" (pcm), [nsamples] "+r" (nsamples), [position] "+r" (position) : [perm] "r" (big_endian ? perm_be : perm_le) : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23"); } else if (nchannels > 1) { /* proper 'pcm' alignment */ int16_t *x = &X[0][position]; int16_t *y = &X[1][position]; __asm__ volatile ( "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n" "1:\n" "sub %[x], %[x], #32\n" "sub %[y], %[y], #32\n" "sub %[position], %[position], #16\n" "vld2.16 {d4, d5, d6, d7}, [%[pcm]]!\n" "vld2.16 {d20, d21, d22, d23}, [%[pcm]]!\n" "vswp q3, q10\n" "vtbl.8 d16, {d4, d5, d6, d7}, d0\n" "vtbl.8 d17, {d4, d5, d6, d7}, d1\n" "vtbl.8 d18, {d4, d5, d6, d7}, d2\n" "vtbl.8 d19, {d4, d5, d6, d7}, d3\n" "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n" "vtbl.8 d16, {d20, d21, d22, d23}, d0\n" "vtbl.8 d17, {d20, d21, d22, d23}, d1\n" "vtbl.8 d18, {d20, d21, d22, d23}, d2\n" "vtbl.8 d19, {d20, d21, d22, d23}, d3\n" "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n" "subs %[nsamples], %[nsamples], #16\n" "bgt 1b\n" : [x] "+r" (x), [y] "+r" (y), [pcm] "+r" (pcm), [nsamples] "+r" (nsamples), [position] "+r" (position) : [perm] "r" (big_endian ? perm_be : perm_le) : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23"); } else { int16_t *x = &X[0][position]; __asm__ volatile ( "vld1.8 {d0, d1, d2, d3}, [%[perm], :128]\n" "1:\n" "sub %[x], %[x], #32\n" "sub %[position], %[position], #16\n" "vld1.8 {d4, d5, d6, d7}, [%[pcm]]!\n" "vtbl.8 d16, {d4, d5, d6, d7}, d0\n" "vtbl.8 d17, {d4, d5, d6, d7}, d1\n" "vtbl.8 d18, {d4, d5, d6, d7}, d2\n" "vtbl.8 d19, {d4, d5, d6, d7}, d3\n" "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n" "subs %[nsamples], %[nsamples], #16\n" "bgt 1b\n" : [x] "+r" (x), [pcm] "+r" (pcm), [nsamples] "+r" (nsamples), [position] "+r" (position) : [perm] "r" (big_endian ? perm_be : perm_le) : "cc", "memory", "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", "d16", "d17", "d18", "d19"); } return position; } #undef PERM_BE #undef PERM_LE static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels) { return sbc_enc_process_input_4s_neon_internal( position, pcm, X, nsamples, nchannels, 1); } static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels) { return sbc_enc_process_input_4s_neon_internal( position, pcm, X, nsamples, nchannels, 0); } static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels) { return sbc_enc_process_input_8s_neon_internal( position, pcm, X, nsamples, nchannels, 1); } static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels) { return sbc_enc_process_input_8s_neon_internal( position, pcm, X, nsamples, nchannels, 0); } void sbc_init_primitives_neon(struct sbc_encoder_state *state) { state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon; state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon; state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon; state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon; state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon; state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon; state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon; state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon; state->implementation_info = "NEON"; } #endif bluez-4.101/sbc/sbc_tables.h0000644000000000000000000006562311766125764012603 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ /* A2DP specification: Appendix B, page 69 */ static const int sbc_offset4[4][4] = { { -1, 0, 0, 0 }, { -2, 0, 0, 1 }, { -2, 0, 0, 1 }, { -2, 0, 0, 1 } }; /* A2DP specification: Appendix B, page 69 */ static const int sbc_offset8[4][8] = { { -2, 0, 0, 0, 0, 0, 0, 1 }, { -3, 0, 0, 0, 0, 0, 1, 2 }, { -4, 0, 0, 0, 0, 0, 1, 2 }, { -4, 0, 0, 0, 0, 0, 1, 2 } }; /* extra bits of precision for the synthesis filter input data */ #define SBCDEC_FIXED_EXTRA_BITS 2 #define SS4(val) ASR(val, SCALE_SPROTO4_TBL) #define SS8(val) ASR(val, SCALE_SPROTO8_TBL) #define SN4(val) ASR(val, SCALE_NPROTO4_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS) #define SN8(val) ASR(val, SCALE_NPROTO8_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS) static const int32_t sbc_proto_4_40m0[] = { SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8), SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8), SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330), SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00), SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7) }; static const int32_t sbc_proto_4_40m1[] = { SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475), SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370), SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b), SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b), SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7) }; static const int32_t sbc_proto_8_80m0[] = { SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100), SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0), SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c), SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705), SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db), SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948), SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200), SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358), SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31), SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170) }; static const int32_t sbc_proto_8_80m1[] = { SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620), SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40), SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01), SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94), SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b), SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68), SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20), SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410), SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da), SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a) }; static const int32_t synmatrix4[8][4] = { { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) }, { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) }, { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) }, { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) }, { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) }, { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }, { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) }, { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) } }; static const int32_t synmatrix8[16][8] = { { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) }, { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988), SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) }, { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac), SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) }, { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10), SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) }, { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) }, { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0), SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) }, { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54), SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) }, { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678), SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) }, { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) }, { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }, { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) }, { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c), SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) }, { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0), SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) }, { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0), SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) } }; /* Uncomment the following line to enable high precision build of SBC encoder */ /* #define SBC_HIGH_PRECISION */ #ifdef SBC_HIGH_PRECISION #define FIXED_A int64_t /* data type for fixed point accumulator */ #define FIXED_T int32_t /* data type for fixed point constants */ #define SBC_FIXED_EXTRA_BITS 16 #else #define FIXED_A int32_t /* data type for fixed point accumulator */ #define FIXED_T int16_t /* data type for fixed point constants */ #define SBC_FIXED_EXTRA_BITS 0 #endif /* A2DP specification: Section 12.8 Tables * * Original values are premultiplied by 2 for better precision (that is the * maximum which is possible without overflows) * * Note: in each block of 8 numbers sign was changed for elements 2 and 7 * in order to compensate the same change applied to cos_table_fixed_4 */ #define SBC_PROTO_FIXED4_SCALE \ ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) #define F_PROTO4(x) (FIXED_A) ((x * 2) * \ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_PROTO4(x) static const FIXED_T _sbc_proto_fixed4[40] = { F(0.00000000E+00), F(5.36548976E-04), -F(1.49188357E-03), F(2.73370904E-03), F(3.83720193E-03), F(3.89205149E-03), F(1.86581691E-03), F(3.06012286E-03), F(1.09137620E-02), F(2.04385087E-02), -F(2.88757392E-02), F(3.21939290E-02), F(2.58767811E-02), F(6.13245186E-03), -F(2.88217274E-02), F(7.76463494E-02), F(1.35593274E-01), F(1.94987841E-01), -F(2.46636662E-01), F(2.81828203E-01), F(2.94315332E-01), F(2.81828203E-01), F(2.46636662E-01), -F(1.94987841E-01), -F(1.35593274E-01), -F(7.76463494E-02), F(2.88217274E-02), F(6.13245186E-03), F(2.58767811E-02), F(3.21939290E-02), F(2.88757392E-02), -F(2.04385087E-02), -F(1.09137620E-02), -F(3.06012286E-03), -F(1.86581691E-03), F(3.89205149E-03), F(3.83720193E-03), F(2.73370904E-03), F(1.49188357E-03), -F(5.36548976E-04), }; #undef F /* * To produce this cosine matrix in Octave: * * b = zeros(4, 8); * for i = 0:3 * for j = 0:7 b(i+1, j+1) = cos((i + 0.5) * (j - 2) * (pi/4)) * endfor * endfor; * printf("%.10f, ", b'); * * Note: in each block of 8 numbers sign was changed for elements 2 and 7 * * Change of sign for element 2 allows to replace constant 1.0 (not * representable in Q15 format) with -1.0 (fine with Q15). * Changed sign for element 7 allows to have more similar constants * and simplify subband filter function code. */ #define SBC_COS_TABLE_FIXED4_SCALE \ ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) #define F_COS4(x) (FIXED_A) ((x) * \ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_COS4(x) static const FIXED_T cos_table_fixed_4[32] = { F(0.7071067812), F(0.9238795325), -F(1.0000000000), F(0.9238795325), F(0.7071067812), F(0.3826834324), F(0.0000000000), F(0.3826834324), -F(0.7071067812), F(0.3826834324), -F(1.0000000000), F(0.3826834324), -F(0.7071067812), -F(0.9238795325), -F(0.0000000000), -F(0.9238795325), -F(0.7071067812), -F(0.3826834324), -F(1.0000000000), -F(0.3826834324), -F(0.7071067812), F(0.9238795325), F(0.0000000000), F(0.9238795325), F(0.7071067812), -F(0.9238795325), -F(1.0000000000), -F(0.9238795325), F(0.7071067812), -F(0.3826834324), -F(0.0000000000), -F(0.3826834324), }; #undef F /* A2DP specification: Section 12.8 Tables * * Original values are premultiplied by 4 for better precision (that is the * maximum which is possible without overflows) * * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 * in order to compensate the same change applied to cos_table_fixed_8 */ #define SBC_PROTO_FIXED8_SCALE \ ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1) #define F_PROTO8(x) (FIXED_A) ((x * 2) * \ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_PROTO8(x) static const FIXED_T _sbc_proto_fixed8[80] = { F(0.00000000E+00), F(1.56575398E-04), F(3.43256425E-04), F(5.54620202E-04), -F(8.23919506E-04), F(1.13992507E-03), F(1.47640169E-03), F(1.78371725E-03), F(2.01182542E-03), F(2.10371989E-03), F(1.99454554E-03), F(1.61656283E-03), F(9.02154502E-04), F(1.78805361E-04), F(1.64973098E-03), F(3.49717454E-03), F(5.65949473E-03), F(8.02941163E-03), F(1.04584443E-02), F(1.27472335E-02), -F(1.46525263E-02), F(1.59045603E-02), F(1.62208471E-02), F(1.53184106E-02), F(1.29371806E-02), F(8.85757540E-03), F(2.92408442E-03), -F(4.91578024E-03), -F(1.46404076E-02), F(2.61098752E-02), F(3.90751381E-02), F(5.31873032E-02), F(6.79989431E-02), F(8.29847578E-02), F(9.75753918E-02), F(1.11196689E-01), -F(1.23264548E-01), F(1.33264415E-01), F(1.40753505E-01), F(1.45389847E-01), F(1.46955068E-01), F(1.45389847E-01), F(1.40753505E-01), F(1.33264415E-01), F(1.23264548E-01), -F(1.11196689E-01), -F(9.75753918E-02), -F(8.29847578E-02), -F(6.79989431E-02), -F(5.31873032E-02), -F(3.90751381E-02), -F(2.61098752E-02), F(1.46404076E-02), -F(4.91578024E-03), F(2.92408442E-03), F(8.85757540E-03), F(1.29371806E-02), F(1.53184106E-02), F(1.62208471E-02), F(1.59045603E-02), F(1.46525263E-02), -F(1.27472335E-02), -F(1.04584443E-02), -F(8.02941163E-03), -F(5.65949473E-03), -F(3.49717454E-03), -F(1.64973098E-03), -F(1.78805361E-04), -F(9.02154502E-04), F(1.61656283E-03), F(1.99454554E-03), F(2.10371989E-03), F(2.01182542E-03), F(1.78371725E-03), F(1.47640169E-03), F(1.13992507E-03), F(8.23919506E-04), -F(5.54620202E-04), -F(3.43256425E-04), -F(1.56575398E-04), }; #undef F /* * To produce this cosine matrix in Octave: * * b = zeros(8, 16); * for i = 0:7 * for j = 0:15 b(i+1, j+1) = cos((i + 0.5) * (j - 4) * (pi/8)) * endfor endfor; * printf("%.10f, ", b'); * * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15 * * Change of sign for element 4 allows to replace constant 1.0 (not * representable in Q15 format) with -1.0 (fine with Q15). * Changed signs for elements 13, 14, 15 allow to have more similar constants * and simplify subband filter function code. */ #define SBC_COS_TABLE_FIXED8_SCALE \ ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS) #define F_COS8(x) (FIXED_A) ((x) * \ ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5) #define F(x) F_COS8(x) static const FIXED_T cos_table_fixed_8[128] = { F(0.7071067812), F(0.8314696123), F(0.9238795325), F(0.9807852804), -F(1.0000000000), F(0.9807852804), F(0.9238795325), F(0.8314696123), F(0.7071067812), F(0.5555702330), F(0.3826834324), F(0.1950903220), F(0.0000000000), F(0.1950903220), F(0.3826834324), F(0.5555702330), -F(0.7071067812), -F(0.1950903220), F(0.3826834324), F(0.8314696123), -F(1.0000000000), F(0.8314696123), F(0.3826834324), -F(0.1950903220), -F(0.7071067812), -F(0.9807852804), -F(0.9238795325), -F(0.5555702330), -F(0.0000000000), -F(0.5555702330), -F(0.9238795325), -F(0.9807852804), -F(0.7071067812), -F(0.9807852804), -F(0.3826834324), F(0.5555702330), -F(1.0000000000), F(0.5555702330), -F(0.3826834324), -F(0.9807852804), -F(0.7071067812), F(0.1950903220), F(0.9238795325), F(0.8314696123), F(0.0000000000), F(0.8314696123), F(0.9238795325), F(0.1950903220), F(0.7071067812), -F(0.5555702330), -F(0.9238795325), F(0.1950903220), -F(1.0000000000), F(0.1950903220), -F(0.9238795325), -F(0.5555702330), F(0.7071067812), F(0.8314696123), -F(0.3826834324), -F(0.9807852804), -F(0.0000000000), -F(0.9807852804), -F(0.3826834324), F(0.8314696123), F(0.7071067812), F(0.5555702330), -F(0.9238795325), -F(0.1950903220), -F(1.0000000000), -F(0.1950903220), -F(0.9238795325), F(0.5555702330), F(0.7071067812), -F(0.8314696123), -F(0.3826834324), F(0.9807852804), F(0.0000000000), F(0.9807852804), -F(0.3826834324), -F(0.8314696123), -F(0.7071067812), F(0.9807852804), -F(0.3826834324), -F(0.5555702330), -F(1.0000000000), -F(0.5555702330), -F(0.3826834324), F(0.9807852804), -F(0.7071067812), -F(0.1950903220), F(0.9238795325), -F(0.8314696123), -F(0.0000000000), -F(0.8314696123), F(0.9238795325), -F(0.1950903220), -F(0.7071067812), F(0.1950903220), F(0.3826834324), -F(0.8314696123), -F(1.0000000000), -F(0.8314696123), F(0.3826834324), F(0.1950903220), -F(0.7071067812), F(0.9807852804), -F(0.9238795325), F(0.5555702330), -F(0.0000000000), F(0.5555702330), -F(0.9238795325), F(0.9807852804), F(0.7071067812), -F(0.8314696123), F(0.9238795325), -F(0.9807852804), -F(1.0000000000), -F(0.9807852804), F(0.9238795325), -F(0.8314696123), F(0.7071067812), -F(0.5555702330), F(0.3826834324), -F(0.1950903220), -F(0.0000000000), -F(0.1950903220), F(0.3826834324), -F(0.5555702330), }; #undef F /* * Enforce 16 byte alignment for the data, which is supposed to be used * with SIMD optimized code. */ #define SBC_ALIGN_BITS 4 #define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1) #ifdef __GNUC__ #define SBC_ALIGNED __attribute__((aligned(1 << (SBC_ALIGN_BITS)))) #else #define SBC_ALIGNED #endif /* * Constant tables for the use in SIMD optimized analysis filters * Each table consists of two parts: * 1. reordered "proto" table * 2. reordered "cos" table * * Due to non-symmetrical reordering, separate tables for "even" * and "odd" cases are needed */ static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_even[40 + 16] = { #define C0 1.0932568993 #define C1 1.3056875580 #define C2 1.3056875580 #define C3 1.6772280856 #define F(x) F_PROTO4(x) F(0.00000000E+00 * C0), F(3.83720193E-03 * C0), F(5.36548976E-04 * C1), F(2.73370904E-03 * C1), F(3.06012286E-03 * C2), F(3.89205149E-03 * C2), F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3), F(1.09137620E-02 * C0), F(2.58767811E-02 * C0), F(2.04385087E-02 * C1), F(3.21939290E-02 * C1), F(7.76463494E-02 * C2), F(6.13245186E-03 * C2), F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3), F(1.35593274E-01 * C0), F(2.94315332E-01 * C0), F(1.94987841E-01 * C1), F(2.81828203E-01 * C1), -F(1.94987841E-01 * C2), F(2.81828203E-01 * C2), F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3), -F(1.35593274E-01 * C0), F(2.58767811E-02 * C0), -F(7.76463494E-02 * C1), F(6.13245186E-03 * C1), -F(2.04385087E-02 * C2), F(3.21939290E-02 * C2), F(0.00000000E+00 * C3), F(2.88217274E-02 * C3), -F(1.09137620E-02 * C0), F(3.83720193E-03 * C0), -F(3.06012286E-03 * C1), F(3.89205149E-03 * C1), -F(5.36548976E-04 * C2), F(2.73370904E-03 * C2), F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3), #undef F #define F(x) F_COS4(x) F(0.7071067812 / C0), F(0.9238795325 / C1), -F(0.7071067812 / C0), F(0.3826834324 / C1), -F(0.7071067812 / C0), -F(0.3826834324 / C1), F(0.7071067812 / C0), -F(0.9238795325 / C1), F(0.3826834324 / C2), -F(1.0000000000 / C3), -F(0.9238795325 / C2), -F(1.0000000000 / C3), F(0.9238795325 / C2), -F(1.0000000000 / C3), -F(0.3826834324 / C2), -F(1.0000000000 / C3), #undef F #undef C0 #undef C1 #undef C2 #undef C3 }; static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_odd[40 + 16] = { #define C0 1.3056875580 #define C1 1.6772280856 #define C2 1.0932568993 #define C3 1.3056875580 #define F(x) F_PROTO4(x) F(2.73370904E-03 * C0), F(5.36548976E-04 * C0), -F(1.49188357E-03 * C1), F(0.00000000E+00 * C1), F(3.83720193E-03 * C2), F(1.09137620E-02 * C2), F(3.89205149E-03 * C3), F(3.06012286E-03 * C3), F(3.21939290E-02 * C0), F(2.04385087E-02 * C0), -F(2.88757392E-02 * C1), F(0.00000000E+00 * C1), F(2.58767811E-02 * C2), F(1.35593274E-01 * C2), F(6.13245186E-03 * C3), F(7.76463494E-02 * C3), F(2.81828203E-01 * C0), F(1.94987841E-01 * C0), -F(2.46636662E-01 * C1), F(0.00000000E+00 * C1), F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2), F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3), F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0), F(2.88217274E-02 * C1), F(0.00000000E+00 * C1), F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2), F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3), F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0), -F(1.86581691E-03 * C1), F(0.00000000E+00 * C1), F(3.83720193E-03 * C2), F(0.00000000E+00 * C2), F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3), #undef F #define F(x) F_COS4(x) F(0.9238795325 / C0), -F(1.0000000000 / C1), F(0.3826834324 / C0), -F(1.0000000000 / C1), -F(0.3826834324 / C0), -F(1.0000000000 / C1), -F(0.9238795325 / C0), -F(1.0000000000 / C1), F(0.7071067812 / C2), F(0.3826834324 / C3), -F(0.7071067812 / C2), -F(0.9238795325 / C3), -F(0.7071067812 / C2), F(0.9238795325 / C3), F(0.7071067812 / C2), -F(0.3826834324 / C3), #undef F #undef C0 #undef C1 #undef C2 #undef C3 }; static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_even[80 + 64] = { #define C0 2.7906148894 #define C1 2.4270044280 #define C2 2.8015616024 #define C3 3.1710363741 #define C4 2.5377944043 #define C5 2.4270044280 #define C6 2.8015616024 #define C7 3.1710363741 #define F(x) F_PROTO8(x) F(0.00000000E+00 * C0), F(2.01182542E-03 * C0), F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), -F(8.23919506E-04 * C4), F(0.00000000E+00 * C4), F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), F(5.65949473E-03 * C0), F(1.29371806E-02 * C0), F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), -F(1.46525263E-02 * C4), F(0.00000000E+00 * C4), F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), F(6.79989431E-02 * C0), F(1.46955068E-01 * C0), F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), -F(1.23264548E-01 * C4), F(0.00000000E+00 * C4), F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), -F(6.79989431E-02 * C0), F(1.29371806E-02 * C0), -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), F(1.46404076E-02 * C4), F(0.00000000E+00 * C4), F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), -F(5.65949473E-03 * C0), F(2.01182542E-03 * C0), -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), -F(9.02154502E-04 * C4), F(0.00000000E+00 * C4), F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), #undef F #define F(x) F_COS8(x) F(0.7071067812 / C0), F(0.8314696123 / C1), -F(0.7071067812 / C0), -F(0.1950903220 / C1), -F(0.7071067812 / C0), -F(0.9807852804 / C1), F(0.7071067812 / C0), -F(0.5555702330 / C1), F(0.7071067812 / C0), F(0.5555702330 / C1), -F(0.7071067812 / C0), F(0.9807852804 / C1), -F(0.7071067812 / C0), F(0.1950903220 / C1), F(0.7071067812 / C0), -F(0.8314696123 / C1), F(0.9238795325 / C2), F(0.9807852804 / C3), F(0.3826834324 / C2), F(0.8314696123 / C3), -F(0.3826834324 / C2), F(0.5555702330 / C3), -F(0.9238795325 / C2), F(0.1950903220 / C3), -F(0.9238795325 / C2), -F(0.1950903220 / C3), -F(0.3826834324 / C2), -F(0.5555702330 / C3), F(0.3826834324 / C2), -F(0.8314696123 / C3), F(0.9238795325 / C2), -F(0.9807852804 / C3), -F(1.0000000000 / C4), F(0.5555702330 / C5), -F(1.0000000000 / C4), -F(0.9807852804 / C5), -F(1.0000000000 / C4), F(0.1950903220 / C5), -F(1.0000000000 / C4), F(0.8314696123 / C5), -F(1.0000000000 / C4), -F(0.8314696123 / C5), -F(1.0000000000 / C4), -F(0.1950903220 / C5), -F(1.0000000000 / C4), F(0.9807852804 / C5), -F(1.0000000000 / C4), -F(0.5555702330 / C5), F(0.3826834324 / C6), F(0.1950903220 / C7), -F(0.9238795325 / C6), -F(0.5555702330 / C7), F(0.9238795325 / C6), F(0.8314696123 / C7), -F(0.3826834324 / C6), -F(0.9807852804 / C7), -F(0.3826834324 / C6), F(0.9807852804 / C7), F(0.9238795325 / C6), -F(0.8314696123 / C7), -F(0.9238795325 / C6), F(0.5555702330 / C7), F(0.3826834324 / C6), -F(0.1950903220 / C7), #undef F #undef C0 #undef C1 #undef C2 #undef C3 #undef C4 #undef C5 #undef C6 #undef C7 }; static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_odd[80 + 64] = { #define C0 2.5377944043 #define C1 2.4270044280 #define C2 2.8015616024 #define C3 3.1710363741 #define C4 2.7906148894 #define C5 2.4270044280 #define C6 2.8015616024 #define C7 3.1710363741 #define F(x) F_PROTO8(x) F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0), F(1.56575398E-04 * C1), F(1.78371725E-03 * C1), F(3.43256425E-04 * C2), F(1.47640169E-03 * C2), F(5.54620202E-04 * C3), F(1.13992507E-03 * C3), F(2.01182542E-03 * C4), F(5.65949473E-03 * C4), F(2.10371989E-03 * C5), F(3.49717454E-03 * C5), F(1.99454554E-03 * C6), F(1.64973098E-03 * C6), F(1.61656283E-03 * C7), F(1.78805361E-04 * C7), F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0), F(8.02941163E-03 * C1), F(1.53184106E-02 * C1), F(1.04584443E-02 * C2), F(1.62208471E-02 * C2), F(1.27472335E-02 * C3), F(1.59045603E-02 * C3), F(1.29371806E-02 * C4), F(6.79989431E-02 * C4), F(8.85757540E-03 * C5), F(5.31873032E-02 * C5), F(2.92408442E-03 * C6), F(3.90751381E-02 * C6), -F(4.91578024E-03 * C7), F(2.61098752E-02 * C7), F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0), F(8.29847578E-02 * C1), F(1.45389847E-01 * C1), F(9.75753918E-02 * C2), F(1.40753505E-01 * C2), F(1.11196689E-01 * C3), F(1.33264415E-01 * C3), F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4), F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5), F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6), F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7), F(0.00000000E+00 * C0), F(1.46404076E-02 * C0), -F(5.31873032E-02 * C1), F(8.85757540E-03 * C1), -F(3.90751381E-02 * C2), F(2.92408442E-03 * C2), -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3), F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4), F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5), F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6), F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7), F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0), -F(3.49717454E-03 * C1), F(2.10371989E-03 * C1), -F(1.64973098E-03 * C2), F(1.99454554E-03 * C2), -F(1.78805361E-04 * C3), F(1.61656283E-03 * C3), F(2.01182542E-03 * C4), F(0.00000000E+00 * C4), F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5), F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6), F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7), #undef F #define F(x) F_COS8(x) -F(1.0000000000 / C0), F(0.8314696123 / C1), -F(1.0000000000 / C0), -F(0.1950903220 / C1), -F(1.0000000000 / C0), -F(0.9807852804 / C1), -F(1.0000000000 / C0), -F(0.5555702330 / C1), -F(1.0000000000 / C0), F(0.5555702330 / C1), -F(1.0000000000 / C0), F(0.9807852804 / C1), -F(1.0000000000 / C0), F(0.1950903220 / C1), -F(1.0000000000 / C0), -F(0.8314696123 / C1), F(0.9238795325 / C2), F(0.9807852804 / C3), F(0.3826834324 / C2), F(0.8314696123 / C3), -F(0.3826834324 / C2), F(0.5555702330 / C3), -F(0.9238795325 / C2), F(0.1950903220 / C3), -F(0.9238795325 / C2), -F(0.1950903220 / C3), -F(0.3826834324 / C2), -F(0.5555702330 / C3), F(0.3826834324 / C2), -F(0.8314696123 / C3), F(0.9238795325 / C2), -F(0.9807852804 / C3), F(0.7071067812 / C4), F(0.5555702330 / C5), -F(0.7071067812 / C4), -F(0.9807852804 / C5), -F(0.7071067812 / C4), F(0.1950903220 / C5), F(0.7071067812 / C4), F(0.8314696123 / C5), F(0.7071067812 / C4), -F(0.8314696123 / C5), -F(0.7071067812 / C4), -F(0.1950903220 / C5), -F(0.7071067812 / C4), F(0.9807852804 / C5), F(0.7071067812 / C4), -F(0.5555702330 / C5), F(0.3826834324 / C6), F(0.1950903220 / C7), -F(0.9238795325 / C6), -F(0.5555702330 / C7), F(0.9238795325 / C6), F(0.8314696123 / C7), -F(0.3826834324 / C6), -F(0.9807852804 / C7), -F(0.3826834324 / C6), F(0.9807852804 / C7), F(0.9238795325 / C6), -F(0.8314696123 / C7), -F(0.9238795325 / C6), F(0.5555702330 / C7), F(0.3826834324 / C6), -F(0.1950903220 / C7), #undef F #undef C0 #undef C1 #undef C2 #undef C3 #undef C4 #undef C5 #undef C6 #undef C7 }; bluez-4.101/sbc/sbc_primitives_neon.h0000644000000000000000000000257211376221745014526 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __SBC_PRIMITIVES_NEON_H #define __SBC_PRIMITIVES_NEON_H #include "sbc_primitives.h" #if defined(__GNUC__) && defined(__ARM_NEON__) && \ !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) #define SBC_BUILD_WITH_NEON_SUPPORT void sbc_init_primitives_neon(struct sbc_encoder_state *encoder_state); #endif #endif bluez-4.101/sbc/sbc_primitives.c0000644000000000000000000004313511571052274013476 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include "sbc.h" #include "sbc_math.h" #include "sbc_tables.h" #include "sbc_primitives.h" #include "sbc_primitives_mmx.h" #include "sbc_primitives_iwmmxt.h" #include "sbc_primitives_neon.h" #include "sbc_primitives_armv6.h" /* * A reference C code of analysis filter with SIMD-friendly tables * reordering and code layout. This code can be used to develop platform * specific SIMD optimizations. Also it may be used as some kind of test * for compiler autovectorization capabilities (who knows, if the compiler * is very good at this stuff, hand optimized assembly may be not strictly * needed for some platform). * * Note: It is also possible to make a simple variant of analysis filter, * which needs only a single constants table without taking care about * even/odd cases. This simple variant of filter can be implemented without * input data permutation. The only thing that would be lost is the * possibility to use pairwise SIMD multiplications. But for some simple * CPU cores without SIMD extensions it can be useful. If anybody is * interested in implementing such variant of a filter, sourcecode from * bluez versions 4.26/4.27 can be used as a reference and the history of * the changes in git repository done around that time may be worth checking. */ static inline void sbc_analyze_four_simd(const int16_t *in, int32_t *out, const FIXED_T *consts) { FIXED_A t1[4]; FIXED_T t2[4]; int hop = 0; /* rounding coefficient */ t1[0] = t1[1] = t1[2] = t1[3] = (FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1); /* low pass polyphase filter */ for (hop = 0; hop < 40; hop += 8) { t1[0] += (FIXED_A) in[hop] * consts[hop]; t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2]; t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3]; t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4]; t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5]; t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6]; t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7]; } /* scaling */ t2[0] = t1[0] >> SBC_PROTO_FIXED4_SCALE; t2[1] = t1[1] >> SBC_PROTO_FIXED4_SCALE; t2[2] = t1[2] >> SBC_PROTO_FIXED4_SCALE; t2[3] = t1[3] >> SBC_PROTO_FIXED4_SCALE; /* do the cos transform */ t1[0] = (FIXED_A) t2[0] * consts[40 + 0]; t1[0] += (FIXED_A) t2[1] * consts[40 + 1]; t1[1] = (FIXED_A) t2[0] * consts[40 + 2]; t1[1] += (FIXED_A) t2[1] * consts[40 + 3]; t1[2] = (FIXED_A) t2[0] * consts[40 + 4]; t1[2] += (FIXED_A) t2[1] * consts[40 + 5]; t1[3] = (FIXED_A) t2[0] * consts[40 + 6]; t1[3] += (FIXED_A) t2[1] * consts[40 + 7]; t1[0] += (FIXED_A) t2[2] * consts[40 + 8]; t1[0] += (FIXED_A) t2[3] * consts[40 + 9]; t1[1] += (FIXED_A) t2[2] * consts[40 + 10]; t1[1] += (FIXED_A) t2[3] * consts[40 + 11]; t1[2] += (FIXED_A) t2[2] * consts[40 + 12]; t1[2] += (FIXED_A) t2[3] * consts[40 + 13]; t1[3] += (FIXED_A) t2[2] * consts[40 + 14]; t1[3] += (FIXED_A) t2[3] * consts[40 + 15]; out[0] = t1[0] >> (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); out[1] = t1[1] >> (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); out[2] = t1[2] >> (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); out[3] = t1[3] >> (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS); } static inline void sbc_analyze_eight_simd(const int16_t *in, int32_t *out, const FIXED_T *consts) { FIXED_A t1[8]; FIXED_T t2[8]; int i, hop; /* rounding coefficient */ t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = (FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1); /* low pass polyphase filter */ for (hop = 0; hop < 80; hop += 16) { t1[0] += (FIXED_A) in[hop] * consts[hop]; t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1]; t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2]; t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3]; t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4]; t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5]; t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6]; t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7]; t1[4] += (FIXED_A) in[hop + 8] * consts[hop + 8]; t1[4] += (FIXED_A) in[hop + 9] * consts[hop + 9]; t1[5] += (FIXED_A) in[hop + 10] * consts[hop + 10]; t1[5] += (FIXED_A) in[hop + 11] * consts[hop + 11]; t1[6] += (FIXED_A) in[hop + 12] * consts[hop + 12]; t1[6] += (FIXED_A) in[hop + 13] * consts[hop + 13]; t1[7] += (FIXED_A) in[hop + 14] * consts[hop + 14]; t1[7] += (FIXED_A) in[hop + 15] * consts[hop + 15]; } /* scaling */ t2[0] = t1[0] >> SBC_PROTO_FIXED8_SCALE; t2[1] = t1[1] >> SBC_PROTO_FIXED8_SCALE; t2[2] = t1[2] >> SBC_PROTO_FIXED8_SCALE; t2[3] = t1[3] >> SBC_PROTO_FIXED8_SCALE; t2[4] = t1[4] >> SBC_PROTO_FIXED8_SCALE; t2[5] = t1[5] >> SBC_PROTO_FIXED8_SCALE; t2[6] = t1[6] >> SBC_PROTO_FIXED8_SCALE; t2[7] = t1[7] >> SBC_PROTO_FIXED8_SCALE; /* do the cos transform */ t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 0; for (i = 0; i < 4; i++) { t1[0] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 0]; t1[0] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 1]; t1[1] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 2]; t1[1] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 3]; t1[2] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 4]; t1[2] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 5]; t1[3] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 6]; t1[3] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 7]; t1[4] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 8]; t1[4] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 9]; t1[5] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 10]; t1[5] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 11]; t1[6] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 12]; t1[6] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 13]; t1[7] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 14]; t1[7] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 15]; } for (i = 0; i < 8; i++) out[i] = t1[i] >> (SBC_COS_TABLE_FIXED8_SCALE - SCALE_OUT_BITS); } static inline void sbc_analyze_4b_4s_simd(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ sbc_analyze_four_simd(x + 12, out, analysis_consts_fixed4_simd_odd); out += out_stride; sbc_analyze_four_simd(x + 8, out, analysis_consts_fixed4_simd_even); out += out_stride; sbc_analyze_four_simd(x + 4, out, analysis_consts_fixed4_simd_odd); out += out_stride; sbc_analyze_four_simd(x + 0, out, analysis_consts_fixed4_simd_even); } static inline void sbc_analyze_4b_8s_simd(int16_t *x, int32_t *out, int out_stride) { /* Analyze blocks */ sbc_analyze_eight_simd(x + 24, out, analysis_consts_fixed8_simd_odd); out += out_stride; sbc_analyze_eight_simd(x + 16, out, analysis_consts_fixed8_simd_even); out += out_stride; sbc_analyze_eight_simd(x + 8, out, analysis_consts_fixed8_simd_odd); out += out_stride; sbc_analyze_eight_simd(x + 0, out, analysis_consts_fixed8_simd_even); } static inline int16_t unaligned16_be(const uint8_t *ptr) { return (int16_t) ((ptr[0] << 8) | ptr[1]); } static inline int16_t unaligned16_le(const uint8_t *ptr) { return (int16_t) (ptr[0] | (ptr[1] << 8)); } /* * Internal helper functions for input data processing. In order to get * optimal performance, it is important to have "nsamples", "nchannels" * and "big_endian" arguments used with this inline function as compile * time constants. */ static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s4_internal( int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels, int big_endian) { /* handle X buffer wraparound */ if (position < nsamples) { if (nchannels > 0) memcpy(&X[0][SBC_X_BUFFER_SIZE - 40], &X[0][position], 36 * sizeof(int16_t)); if (nchannels > 1) memcpy(&X[1][SBC_X_BUFFER_SIZE - 40], &X[1][position], 36 * sizeof(int16_t)); position = SBC_X_BUFFER_SIZE - 40; } #define PCM(i) (big_endian ? \ unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2)) /* copy/permutate audio samples */ while ((nsamples -= 8) >= 0) { position -= 8; if (nchannels > 0) { int16_t *x = &X[0][position]; x[0] = PCM(0 + 7 * nchannels); x[1] = PCM(0 + 3 * nchannels); x[2] = PCM(0 + 6 * nchannels); x[3] = PCM(0 + 4 * nchannels); x[4] = PCM(0 + 0 * nchannels); x[5] = PCM(0 + 2 * nchannels); x[6] = PCM(0 + 1 * nchannels); x[7] = PCM(0 + 5 * nchannels); } if (nchannels > 1) { int16_t *x = &X[1][position]; x[0] = PCM(1 + 7 * nchannels); x[1] = PCM(1 + 3 * nchannels); x[2] = PCM(1 + 6 * nchannels); x[3] = PCM(1 + 4 * nchannels); x[4] = PCM(1 + 0 * nchannels); x[5] = PCM(1 + 2 * nchannels); x[6] = PCM(1 + 1 * nchannels); x[7] = PCM(1 + 5 * nchannels); } pcm += 16 * nchannels; } #undef PCM return position; } static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s8_internal( int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels, int big_endian) { /* handle X buffer wraparound */ if (position < nsamples) { if (nchannels > 0) memcpy(&X[0][SBC_X_BUFFER_SIZE - 72], &X[0][position], 72 * sizeof(int16_t)); if (nchannels > 1) memcpy(&X[1][SBC_X_BUFFER_SIZE - 72], &X[1][position], 72 * sizeof(int16_t)); position = SBC_X_BUFFER_SIZE - 72; } #define PCM(i) (big_endian ? \ unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2)) /* copy/permutate audio samples */ while ((nsamples -= 16) >= 0) { position -= 16; if (nchannels > 0) { int16_t *x = &X[0][position]; x[0] = PCM(0 + 15 * nchannels); x[1] = PCM(0 + 7 * nchannels); x[2] = PCM(0 + 14 * nchannels); x[3] = PCM(0 + 8 * nchannels); x[4] = PCM(0 + 13 * nchannels); x[5] = PCM(0 + 9 * nchannels); x[6] = PCM(0 + 12 * nchannels); x[7] = PCM(0 + 10 * nchannels); x[8] = PCM(0 + 11 * nchannels); x[9] = PCM(0 + 3 * nchannels); x[10] = PCM(0 + 6 * nchannels); x[11] = PCM(0 + 0 * nchannels); x[12] = PCM(0 + 5 * nchannels); x[13] = PCM(0 + 1 * nchannels); x[14] = PCM(0 + 4 * nchannels); x[15] = PCM(0 + 2 * nchannels); } if (nchannels > 1) { int16_t *x = &X[1][position]; x[0] = PCM(1 + 15 * nchannels); x[1] = PCM(1 + 7 * nchannels); x[2] = PCM(1 + 14 * nchannels); x[3] = PCM(1 + 8 * nchannels); x[4] = PCM(1 + 13 * nchannels); x[5] = PCM(1 + 9 * nchannels); x[6] = PCM(1 + 12 * nchannels); x[7] = PCM(1 + 10 * nchannels); x[8] = PCM(1 + 11 * nchannels); x[9] = PCM(1 + 3 * nchannels); x[10] = PCM(1 + 6 * nchannels); x[11] = PCM(1 + 0 * nchannels); x[12] = PCM(1 + 5 * nchannels); x[13] = PCM(1 + 1 * nchannels); x[14] = PCM(1 + 4 * nchannels); x[15] = PCM(1 + 2 * nchannels); } pcm += 32 * nchannels; } #undef PCM return position; } /* * Input data processing functions. The data is endian converted if needed, * channels are deintrleaved and audio samples are reordered for use in * SIMD-friendly analysis filter function. The results are put into "X" * array, getting appended to the previous data (or it is better to say * prepended, as the buffer is filled from top to bottom). Old data is * discarded when neededed, but availability of (10 * nrof_subbands) * contiguous samples is always guaranteed for the input to the analysis * filter. This is achieved by copying a sufficient part of old data * to the top of the buffer on buffer wraparound. */ static int sbc_enc_process_input_4s_le(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels) { if (nchannels > 1) return sbc_encoder_process_input_s4_internal( position, pcm, X, nsamples, 2, 0); else return sbc_encoder_process_input_s4_internal( position, pcm, X, nsamples, 1, 0); } static int sbc_enc_process_input_4s_be(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels) { if (nchannels > 1) return sbc_encoder_process_input_s4_internal( position, pcm, X, nsamples, 2, 1); else return sbc_encoder_process_input_s4_internal( position, pcm, X, nsamples, 1, 1); } static int sbc_enc_process_input_8s_le(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels) { if (nchannels > 1) return sbc_encoder_process_input_s8_internal( position, pcm, X, nsamples, 2, 0); else return sbc_encoder_process_input_s8_internal( position, pcm, X, nsamples, 1, 0); } static int sbc_enc_process_input_8s_be(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels) { if (nchannels > 1) return sbc_encoder_process_input_s8_internal( position, pcm, X, nsamples, 2, 1); else return sbc_encoder_process_input_s8_internal( position, pcm, X, nsamples, 1, 1); } /* Supplementary function to count the number of leading zeros */ static inline int sbc_clz(uint32_t x) { #ifdef __GNUC__ return __builtin_clz(x); #else /* TODO: this should be replaced with something better if good * performance is wanted when using compilers other than gcc */ int cnt = 0; while (x) { cnt++; x >>= 1; } return 32 - cnt; #endif } static void sbc_calc_scalefactors( int32_t sb_sample_f[16][2][8], uint32_t scale_factor[2][8], int blocks, int channels, int subbands) { int ch, sb, blk; for (ch = 0; ch < channels; ch++) { for (sb = 0; sb < subbands; sb++) { uint32_t x = 1 << SCALE_OUT_BITS; for (blk = 0; blk < blocks; blk++) { int32_t tmp = fabs(sb_sample_f[blk][ch][sb]); if (tmp != 0) x |= tmp - 1; } scale_factor[ch][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x); } } } static int sbc_calc_scalefactors_j( int32_t sb_sample_f[16][2][8], uint32_t scale_factor[2][8], int blocks, int subbands) { int blk, joint = 0; int32_t tmp0, tmp1; uint32_t x, y; /* last subband does not use joint stereo */ int sb = subbands - 1; x = 1 << SCALE_OUT_BITS; y = 1 << SCALE_OUT_BITS; for (blk = 0; blk < blocks; blk++) { tmp0 = fabs(sb_sample_f[blk][0][sb]); tmp1 = fabs(sb_sample_f[blk][1][sb]); if (tmp0 != 0) x |= tmp0 - 1; if (tmp1 != 0) y |= tmp1 - 1; } scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x); scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y); /* the rest of subbands can use joint stereo */ while (--sb >= 0) { int32_t sb_sample_j[16][2]; x = 1 << SCALE_OUT_BITS; y = 1 << SCALE_OUT_BITS; for (blk = 0; blk < blocks; blk++) { tmp0 = sb_sample_f[blk][0][sb]; tmp1 = sb_sample_f[blk][1][sb]; sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1); sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1); tmp0 = fabs(tmp0); tmp1 = fabs(tmp1); if (tmp0 != 0) x |= tmp0 - 1; if (tmp1 != 0) y |= tmp1 - 1; } scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x); scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y); x = 1 << SCALE_OUT_BITS; y = 1 << SCALE_OUT_BITS; for (blk = 0; blk < blocks; blk++) { tmp0 = fabs(sb_sample_j[blk][0]); tmp1 = fabs(sb_sample_j[blk][1]); if (tmp0 != 0) x |= tmp0 - 1; if (tmp1 != 0) y |= tmp1 - 1; } x = (31 - SCALE_OUT_BITS) - sbc_clz(x); y = (31 - SCALE_OUT_BITS) - sbc_clz(y); /* decide whether to use joint stereo for this subband */ if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) { joint |= 1 << (subbands - 1 - sb); scale_factor[0][sb] = x; scale_factor[1][sb] = y; for (blk = 0; blk < blocks; blk++) { sb_sample_f[blk][0][sb] = sb_sample_j[blk][0]; sb_sample_f[blk][1][sb] = sb_sample_j[blk][1]; } } } /* bitmask with the information about subbands using joint stereo */ return joint; } /* * Detect CPU features and setup function pointers */ void sbc_init_primitives(struct sbc_encoder_state *state) { /* Default implementation for analyze functions */ state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_simd; state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_simd; /* Default implementation for input reordering / deinterleaving */ state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le; state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be; state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le; state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be; /* Default implementation for scale factors calculation */ state->sbc_calc_scalefactors = sbc_calc_scalefactors; state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j; state->implementation_info = "Generic C"; /* X86/AMD64 optimizations */ #ifdef SBC_BUILD_WITH_MMX_SUPPORT sbc_init_primitives_mmx(state); #endif /* ARM optimizations */ #ifdef SBC_BUILD_WITH_ARMV6_SUPPORT sbc_init_primitives_armv6(state); #endif #ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT sbc_init_primitives_iwmmxt(state); #endif #ifdef SBC_BUILD_WITH_NEON_SUPPORT sbc_init_primitives_neon(state); #endif } bluez-4.101/sbc/sbc_primitives_iwmmxt.h0000644000000000000000000000266411571052274015112 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2010 Keith Mok * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __SBC_PRIMITIVES_IWMMXT_H #define __SBC_PRIMITIVES_IWMMXT_H #include "sbc_primitives.h" #if defined(__GNUC__) && defined(__IWMMXT__) && \ !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) #define SBC_BUILD_WITH_IWMMXT_SUPPORT void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *encoder_state); #endif #endif bluez-4.101/sbc/formats.h0000644000000000000000000000334611376221745012140 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #if __BYTE_ORDER == __LITTLE_ENDIAN #define COMPOSE_ID(a,b,c,d) ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24)) #define LE_SHORT(v) (v) #define LE_INT(v) (v) #define BE_SHORT(v) bswap_16(v) #define BE_INT(v) bswap_32(v) #elif __BYTE_ORDER == __BIG_ENDIAN #define COMPOSE_ID(a,b,c,d) ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24)) #define LE_SHORT(v) bswap_16(v) #define LE_INT(v) bswap_32(v) #define BE_SHORT(v) (v) #define BE_INT(v) (v) #else #error "Wrong endian" #endif #define AU_MAGIC COMPOSE_ID('.','s','n','d') #define AU_FMT_ULAW 1 #define AU_FMT_LIN8 2 #define AU_FMT_LIN16 3 struct au_header { uint32_t magic; /* '.snd' */ uint32_t hdr_size; /* size of header (min 24) */ uint32_t data_size; /* size of data */ uint32_t encoding; /* see to AU_FMT_XXXX */ uint32_t sample_rate; /* sample rate */ uint32_t channels; /* number of channels (voices) */ }; bluez-4.101/sbc/sbc_primitives.h0000644000000000000000000000577011766125764013521 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __SBC_PRIMITIVES_H #define __SBC_PRIMITIVES_H #define SCALE_OUT_BITS 15 #define SBC_X_BUFFER_SIZE 328 #ifdef __GNUC__ #define SBC_ALWAYS_INLINE inline __attribute__((always_inline)) #else #define SBC_ALWAYS_INLINE inline #endif struct sbc_encoder_state { int position; int16_t SBC_ALIGNED X[2][SBC_X_BUFFER_SIZE]; /* Polyphase analysis filter for 4 subbands configuration, * it handles 4 blocks at once */ void (*sbc_analyze_4b_4s)(int16_t *x, int32_t *out, int out_stride); /* Polyphase analysis filter for 8 subbands configuration, * it handles 4 blocks at once */ void (*sbc_analyze_4b_8s)(int16_t *x, int32_t *out, int out_stride); /* Process input data (deinterleave, endian conversion, reordering), * depending on the number of subbands and input data byte order */ int (*sbc_enc_process_input_4s_le)(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels); int (*sbc_enc_process_input_4s_be)(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels); int (*sbc_enc_process_input_8s_le)(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels); int (*sbc_enc_process_input_8s_be)(int position, const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE], int nsamples, int nchannels); /* Scale factors calculation */ void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8], uint32_t scale_factor[2][8], int blocks, int channels, int subbands); /* Scale factors calculation with joint stereo support */ int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8], uint32_t scale_factor[2][8], int blocks, int subbands); const char *implementation_info; }; /* * Initialize pointers to the functions which are the basic "building bricks" * of SBC codec. Best implementation is selected based on target CPU * capabilities. */ void sbc_init_primitives(struct sbc_encoder_state *encoder_state); #endif bluez-4.101/sbc/sbcenc.c0000644000000000000000000001607711571052274011716 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) encoder * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "sbc.h" #include "formats.h" static int verbose = 0; #define BUF_SIZE 32768 static unsigned char input[BUF_SIZE], output[BUF_SIZE + BUF_SIZE / 4]; static void encode(char *filename, int subbands, int bitpool, int joint, int dualchannel, int snr, int blocks) { struct au_header au_hdr; sbc_t sbc; int fd, size, srate, codesize, nframes; ssize_t encoded; ssize_t len; if (sizeof(au_hdr) != 24) { /* Sanity check just in case */ fprintf(stderr, "FIXME: sizeof(au_hdr) != 24\n"); return; } if (strcmp(filename, "-")) { fd = open(filename, O_RDONLY); if (fd < 0) { fprintf(stderr, "Can't open file %s: %s\n", filename, strerror(errno)); return; } } else fd = fileno(stdin); len = read(fd, &au_hdr, sizeof(au_hdr)); if (len < (ssize_t) sizeof(au_hdr)) { if (fd > fileno(stderr)) fprintf(stderr, "Can't read header from file %s: %s\n", filename, strerror(errno)); else perror("Can't read audio header"); goto done; } if (au_hdr.magic != AU_MAGIC || BE_INT(au_hdr.hdr_size) > 128 || BE_INT(au_hdr.hdr_size) < sizeof(au_hdr) || BE_INT(au_hdr.encoding) != AU_FMT_LIN16) { fprintf(stderr, "Not in Sun/NeXT audio S16_BE format\n"); goto done; } sbc_init(&sbc, 0L); switch (BE_INT(au_hdr.sample_rate)) { case 16000: sbc.frequency = SBC_FREQ_16000; break; case 32000: sbc.frequency = SBC_FREQ_32000; break; case 44100: sbc.frequency = SBC_FREQ_44100; break; case 48000: sbc.frequency = SBC_FREQ_48000; break; } srate = BE_INT(au_hdr.sample_rate); sbc.subbands = subbands == 4 ? SBC_SB_4 : SBC_SB_8; if (BE_INT(au_hdr.channels) == 1) { sbc.mode = SBC_MODE_MONO; if (joint || dualchannel) { fprintf(stderr, "Audio is mono but joint or " "dualchannel mode has been specified\n"); goto done; } } else if (joint && !dualchannel) sbc.mode = SBC_MODE_JOINT_STEREO; else if (!joint && dualchannel) sbc.mode = SBC_MODE_DUAL_CHANNEL; else if (!joint && !dualchannel) sbc.mode = SBC_MODE_STEREO; else { fprintf(stderr, "Both joint and dualchannel mode have been " "specified\n"); goto done; } sbc.endian = SBC_BE; /* Skip extra bytes of the header if any */ if (read(fd, input, BE_INT(au_hdr.hdr_size) - len) < 0) goto done; sbc.bitpool = bitpool; sbc.allocation = snr ? SBC_AM_SNR : SBC_AM_LOUDNESS; sbc.blocks = blocks == 4 ? SBC_BLK_4 : blocks == 8 ? SBC_BLK_8 : blocks == 12 ? SBC_BLK_12 : SBC_BLK_16; if (verbose) { fprintf(stderr, "encoding %s with rate %d, %d blocks, " "%d subbands, %d bits, allocation method %s, " "and mode %s\n", filename, srate, blocks, subbands, bitpool, sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS", sbc.mode == SBC_MODE_MONO ? "MONO" : sbc.mode == SBC_MODE_STEREO ? "STEREO" : "JOINTSTEREO"); } codesize = sbc_get_codesize(&sbc); nframes = sizeof(input) / codesize; while (1) { unsigned char *inp, *outp; /* read data for up to 'nframes' frames of input data */ size = read(fd, input, codesize * nframes); if (size < 0) { /* Something really bad happened */ perror("Can't read audio data"); break; } if (size < codesize) { /* Not enough data for encoding even a single frame */ break; } /* encode all the data from the input buffer in a loop */ inp = input; outp = output; while (size >= codesize) { len = sbc_encode(&sbc, inp, codesize, outp, sizeof(output) - (outp - output), &encoded); if (len != codesize || encoded <= 0) { fprintf(stderr, "sbc_encode fail, len=%zd, encoded=%lu\n", len, (unsigned long) encoded); break; } size -= len; inp += len; outp += encoded; } len = write(fileno(stdout), output, outp - output); if (len != outp - output) { perror("Can't write SBC output"); break; } if (size != 0) { /* * sbc_encode failure has been detected earlier or end * of file reached (have trailing partial data which is * insufficient to encode SBC frame) */ break; } } sbc_finish(&sbc); done: if (fd > fileno(stderr)) close(fd); } static void usage(void) { printf("SBC encoder utility ver %s\n", VERSION); printf("Copyright (c) 2004-2010 Marcel Holtmann\n\n"); printf("Usage:\n" "\tsbcenc [options] file(s)\n" "\n"); printf("Options:\n" "\t-h, --help Display help\n" "\t-v, --verbose Verbose mode\n" "\t-s, --subbands Number of subbands to use (4 or 8)\n" "\t-b, --bitpool Bitpool value (default is 32)\n" "\t-j, --joint Joint stereo\n" "\t-d, --dualchannel Dual channel\n" "\t-S, --snr Use SNR mode (default is loudness)\n" "\t-B, --blocks Number of blocks (4, 8, 12 or 16)\n" "\n"); } static struct option main_options[] = { { "help", 0, 0, 'h' }, { "verbose", 0, 0, 'v' }, { "subbands", 1, 0, 's' }, { "bitpool", 1, 0, 'b' }, { "joint", 0, 0, 'j' }, { "dualchannel",0, 0, 'd' }, { "snr", 0, 0, 'S' }, { "blocks", 1, 0, 'B' }, { 0, 0, 0, 0 } }; int main(int argc, char *argv[]) { int i, opt, subbands = 8, bitpool = 32, joint = 0, dualchannel = 0; int snr = 0, blocks = 16; while ((opt = getopt_long(argc, argv, "+hvs:b:jdSB:", main_options, NULL)) != -1) { switch(opt) { case 'h': usage(); exit(0); case 'v': verbose = 1; break; case 's': subbands = atoi(optarg); if (subbands != 8 && subbands != 4) { fprintf(stderr, "Invalid subbands\n"); exit(1); } break; case 'b': bitpool = atoi(optarg); break; case 'j': joint = 1; break; case 'd': dualchannel = 1; break; case 'S': snr = 1; break; case 'B': blocks = atoi(optarg); if (blocks != 16 && blocks != 12 && blocks != 8 && blocks != 4) { fprintf(stderr, "Invalid blocks\n"); exit(1); } break; default: usage(); exit(1); } } argc -= optind; argv += optind; optind = 0; if (argc < 1) { usage(); exit(1); } for (i = 0; i < argc; i++) encode(argv[i], subbands, bitpool, joint, dualchannel, snr, blocks); return 0; } bluez-4.101/sbc/sbc_primitives_mmx.h0000644000000000000000000000261211376221745014363 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __SBC_PRIMITIVES_MMX_H #define __SBC_PRIMITIVES_MMX_H #include "sbc_primitives.h" #if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__)) && \ !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) #define SBC_BUILD_WITH_MMX_SUPPORT void sbc_init_primitives_mmx(struct sbc_encoder_state *encoder_state); #endif #endif bluez-4.101/sbc/sbc_primitives_armv6.h0000644000000000000000000000351511571052274014614 00000000000000/* * * Bluetooth low-complexity, subband codec (SBC) library * * Copyright (C) 2008-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2004-2005 Henryk Ploetz * Copyright (C) 2005-2006 Brad Midgley * * * 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. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __SBC_PRIMITIVES_ARMV6_H #define __SBC_PRIMITIVES_ARMV6_H #include "sbc_primitives.h" #if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \ defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \ defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \ defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \ defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \ defined(__ARM_ARCH_7M__) #define SBC_HAVE_ARMV6 1 #endif #if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \ defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \ defined(__ARM_EABI__) && !defined(__ARM_NEON__) && \ (!defined(__thumb__) || defined(__thumb2__)) #define SBC_BUILD_WITH_ARMV6_SUPPORT void sbc_init_primitives_armv6(struct sbc_encoder_state *encoder_state); #endif #endif bluez-4.101/ylwrap0000755000000000000000000001435711771117507011014 00000000000000#! /bin/sh # ylwrap - wrapper for lex/yacc invocations. scriptversion=2011-08-25.18; # UTC # Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005, # 2007, 2009, 2010, 2011 Free Software Foundation, Inc. # # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . case "$1" in '') echo "$0: No files given. Try \`$0 --help' for more information." 1>&2 exit 1 ;; --basedir) basedir=$2 shift 2 ;; -h|--h*) cat <<\EOF Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]... Wrapper for lex/yacc invocations, renaming files as desired. INPUT is the input file OUTPUT is one file PROG generates DESIRED is the file we actually want instead of OUTPUT PROGRAM is program to run ARGS are passed to PROG Any number of OUTPUT,DESIRED pairs may be used. Report bugs to . EOF exit $? ;; -v|--v*) echo "ylwrap $scriptversion" exit $? ;; esac # The input. input="$1" shift case "$input" in [\\/]* | ?:[\\/]*) # Absolute path; do nothing. ;; *) # Relative path. Make it absolute. input="`pwd`/$input" ;; esac pairlist= while test "$#" -ne 0; do if test "$1" = "--"; then shift break fi pairlist="$pairlist $1" shift done # The program to run. prog="$1" shift # Make any relative path in $prog absolute. case "$prog" in [\\/]* | ?:[\\/]*) ;; *[\\/]*) prog="`pwd`/$prog" ;; esac # FIXME: add hostname here for parallel makes that run commands on # other machines. But that might take us over the 14-char limit. dirname=ylwrap$$ do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 mkdir $dirname || exit 1 cd $dirname case $# in 0) "$prog" "$input" ;; *) "$prog" "$@" "$input" ;; esac ret=$? if test $ret -eq 0; then set X $pairlist shift first=yes # Since DOS filename conventions don't allow two dots, # the DOS version of Bison writes out y_tab.c instead of y.tab.c # and y_tab.h instead of y.tab.h. Test to see if this is the case. y_tab_nodot="no" if test -f y_tab.c || test -f y_tab.h; then y_tab_nodot="yes" fi # The directory holding the input. input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'` # Quote $INPUT_DIR so we can use it in a regexp. # FIXME: really we should care about more than `.' and `\'. input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'` while test "$#" -ne 0; do from="$1" # Handle y_tab.c and y_tab.h output by DOS if test $y_tab_nodot = "yes"; then if test $from = "y.tab.c"; then from="y_tab.c" else if test $from = "y.tab.h"; then from="y_tab.h" fi fi fi if test -f "$from"; then # If $2 is an absolute path name, then just use that, # otherwise prepend `../'. case "$2" in [\\/]* | ?:[\\/]*) target="$2";; *) target="../$2";; esac # We do not want to overwrite a header file if it hasn't # changed. This avoid useless recompilations. However the # parser itself (the first file) should always be updated, # because it is the destination of the .y.c rule in the # Makefile. Divert the output of all other files to a temporary # file so we can compare them to existing versions. if test $first = no; then realtarget="$target" target="tmp-`echo $target | sed s/.*[\\/]//g`" fi # Edit out `#line' or `#' directives. # # We don't want the resulting debug information to point at # an absolute srcdir; it is better for it to just mention the # .y file with no path. # # We want to use the real output file name, not yy.lex.c for # instance. # # We want the include guards to be adjusted too. FROM=`echo "$from" | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` TARGET=`echo "$2" | sed \ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'` sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \ -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$? # Check whether header files must be updated. if test $first = no; then if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then echo "$2" is unchanged rm -f "$target" else echo updating "$2" mv -f "$target" "$realtarget" fi fi else # A missing file is only an error for the first file. This # is a blatant hack to let us support using "yacc -d". If -d # is not specified, we don't want an error when the header # file is "missing". if test $first = yes; then ret=1 fi fi shift shift first=no done else ret=$? fi # Remove the directory. cd .. rm -rf $dirname exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: bluez-4.101/NEWS0000644000000000000000000000000011071665350010220 00000000000000bluez-4.101/bluez.pc.in0000644000000000000000000000033111071665350011602 00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ Name: BlueZ Description: Bluetooth protocol stack for Linux Version: @VERSION@ Libs: -L${libdir} -lbluetooth Cflags: -I${includedir} bluez-4.101/configure0000755000000000000000000163461511771117511011460 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for bluez 4.101. # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || ( ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO PATH=/empty FPATH=/empty; export PATH FPATH test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" SHELL=${CONFIG_SHELL-/bin/sh} test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='bluez' PACKAGE_TARNAME='bluez' PACKAGE_VERSION='4.101' PACKAGE_STRING='bluez 4.101' PACKAGE_BUGREPORT='' PACKAGE_URL='' ac_default_prefix=/usr/local # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS SYSTEMD_FALSE SYSTEMD_TRUE SYSTEMD_UNITDIR GATTMODULES_FALSE GATTMODULES_TRUE WIIMOTEPLUGIN_FALSE WIIMOTEPLUGIN_TRUE DBUSOOBPLUGIN_FALSE DBUSOOBPLUGIN_TRUE MAEMO6PLUGIN_FALSE MAEMO6PLUGIN_TRUE DATAFILES_FALSE DATAFILES_TRUE DFUTOOL_FALSE DFUTOOL_TRUE HID2HCI_FALSE HID2HCI_TRUE PCMCIA_FALSE PCMCIA_TRUE BCCMD_FALSE BCCMD_TRUE TOOLS_FALSE TOOLS_TRUE TEST_FALSE TEST_TRUE CUPS_FALSE CUPS_TRUE DUND_FALSE DUND_TRUE PAND_FALSE PAND_TRUE HIDD_FALSE HIDD_TRUE PNATPLUGIN_FALSE PNATPLUGIN_TRUE READLINE_FALSE READLINE_TRUE HAL_FALSE HAL_TRUE MCAP_FALSE MCAP_TRUE HEALTHPLUGIN_FALSE HEALTHPLUGIN_TRUE SERVICEPLUGIN_FALSE SERVICEPLUGIN_TRUE SAPPLUGIN_FALSE SAPPLUGIN_TRUE NETWORKPLUGIN_FALSE NETWORKPLUGIN_TRUE SERIALPLUGIN_FALSE SERIALPLUGIN_TRUE INPUTPLUGIN_FALSE INPUTPLUGIN_TRUE AUDIOPLUGIN_FALSE AUDIOPLUGIN_TRUE GSTREAMER_FALSE GSTREAMER_TRUE ALSA_FALSE ALSA_TRUE SBC_FALSE SBC_TRUE USB_FALSE USB_TRUE SNDFILE_FALSE SNDFILE_TRUE MISC_LDFLAGS MISC_CFLAGS TELEPHONY_DRIVER SAP_DRIVER CHECK_LIBS CHECK_CFLAGS READLINE_LIBS SNDFILE_LIBS SNDFILE_CFLAGS UDEV_LIBS UDEV_CFLAGS USB_LIBS USB_CFLAGS GSTREAMER_PLUGINSDIR GSTREAMER_LIBS GSTREAMER_CFLAGS ALSA_LIBS ALSA_CFLAGS GLIB_LIBS GLIB_CFLAGS DBUS_LIBS DBUS_CFLAGS CPP OTOOL64 OTOOL LIPO NMEDIT DSYMUTIL MANIFEST_TOOL RANLIB ac_ct_AR AR DLLTOOL OBJDUMP LN_S NM ac_ct_DUMPBIN DUMPBIN LD FGREP EGREP GREP SED host_os host_vendor host_cpu host build_os build_vendor build_cpu build LIBTOOL LEXLIB LEX_OUTPUT_ROOT LEX YFLAGS YACC am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC WARNING_CFLAGS UDEV_DIR STORAGEDIR CONFIGDIR PKG_CONFIG_LIBDIR PKG_CONFIG_PATH PKG_CONFIG MAINT MAINTAINER_MODE_FALSE MAINTAINER_MODE_TRUE AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_maintainer_mode enable_dependency_tracking enable_static enable_shared with_pic enable_fast_install with_gnu_ld with_sysroot enable_libtool_lock with_ouifile enable_optimization enable_fortify enable_pie enable_network enable_sap with_sap enable_serial enable_input enable_audio enable_service enable_health enable_pnat enable_gstreamer enable_alsa enable_usb enable_tools enable_bccmd enable_pcmcia enable_hid2hci enable_dfutool enable_hidd enable_pand enable_dund enable_cups enable_test enable_datafiles enable_debug with_telephony enable_maemo6 enable_dbusoob enable_wiimote enable_hal enable_gatt with_systemdunitdir ' ac_precious_vars='build_alias host_alias target_alias PKG_CONFIG PKG_CONFIG_PATH PKG_CONFIG_LIBDIR CC CFLAGS LDFLAGS LIBS CPPFLAGS YACC YFLAGS CPP DBUS_CFLAGS DBUS_LIBS GLIB_CFLAGS GLIB_LIBS ALSA_CFLAGS ALSA_LIBS GSTREAMER_CFLAGS GSTREAMER_LIBS USB_CFLAGS USB_LIBS UDEV_CFLAGS UDEV_LIBS SNDFILE_CFLAGS SNDFILE_LIBS CHECK_CFLAGS CHECK_LIBS' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures bluez 4.101 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/bluez] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of bluez 4.101:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: `make V=1') --disable-silent-rules verbose build output (undo: `make V=0') --enable-maintainer-mode enable make rules and dependencies not useful (and sometimes confusing) to the casual installer --disable-dependency-tracking speeds up one-time build --enable-dependency-tracking do not reject slow dependency extractors --enable-static[=PKGS] build static libraries [default=no] --enable-shared[=PKGS] build shared libraries [default=yes] --enable-fast-install[=PKGS] optimize for fast installation [default=yes] --disable-libtool-lock avoid locking (might break parallel builds) --disable-optimization disable code optimization --disable-fortify disable compile time buffer checks --disable-pie disable position independent executables flag --disable-network disable network plugin --enable-sap enable sap plugin --disable-serial disable serial plugin --disable-input disable input plugin --disable-audio disable audio plugin --disable-service disable service plugin --enable-health enable health plugin --enable-pnat enable pnat plugin --enable-gstreamer enable GStreamer support --enable-alsa enable ALSA support --enable-usb enable USB support --enable-tools install Bluetooth utilities --enable-bccmd install BCCMD interface utility --enable-pcmcia install PCMCIA serial script --enable-hid2hci install HID mode switching utility --enable-dfutool install DFU firmware upgrade utility --enable-hidd install HID daemon --enable-pand install PAN daemon --enable-dund install DUN daemon --enable-cups install CUPS backend support --enable-test install test programs --enable-datafiles install Bluetooth configuration and data files --enable-debug enable compiling with debugging information --enable-maemo6 compile with maemo6 plugin --enable-dbusoob compile with D-Bus OOB plugin --enable-wiimote compile with Wii Remote plugin --enable-hal Use HAL to determine adapter class --enable-gatt enable gatt module Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use both] --with-gnu-ld assume the C compiler uses GNU ld [default=no] --with-sysroot=DIR Search for dependent libraries within DIR (or the compiler's sysroot if not specified). --with-ouifile=PATH Path to the oui.txt file [auto] --with-sap=DRIVER select SAP driver --with-telephony=DRIVER select telephony driver --with-systemdunitdir=DIR path to systemd system service directory Some influential environment variables: PKG_CONFIG path to pkg-config utility PKG_CONFIG_PATH directories to add to pkg-config's search path PKG_CONFIG_LIBDIR path overriding pkg-config's built-in search path CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory YACC The `Yet Another Compiler Compiler' implementation to use. Defaults to the first program found out of: `bison -y', `byacc', `yacc'. YFLAGS The list of arguments that will be passed by default to $YACC. This script will default YFLAGS to the empty string to avoid a default value of `-d' given by some make applications. CPP C preprocessor DBUS_CFLAGS C compiler flags for DBUS, overriding pkg-config DBUS_LIBS linker flags for DBUS, overriding pkg-config GLIB_CFLAGS C compiler flags for GLIB, overriding pkg-config GLIB_LIBS linker flags for GLIB, overriding pkg-config ALSA_CFLAGS C compiler flags for ALSA, overriding pkg-config ALSA_LIBS linker flags for ALSA, overriding pkg-config GSTREAMER_CFLAGS C compiler flags for GSTREAMER, overriding pkg-config GSTREAMER_LIBS linker flags for GSTREAMER, overriding pkg-config USB_CFLAGS C compiler flags for USB, overriding pkg-config USB_LIBS linker flags for USB, overriding pkg-config UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config UDEV_LIBS linker flags for UDEV, overriding pkg-config SNDFILE_CFLAGS C compiler flags for SNDFILE, overriding pkg-config SNDFILE_LIBS linker flags for SNDFILE, overriding pkg-config CHECK_CFLAGS C compiler flags for CHECK, overriding pkg-config CHECK_LIBS linker flags for CHECK, overriding pkg-config Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF bluez configure 4.101 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_func LINENO FUNC VAR # ---------------------------------- # Tests whether FUNC exists, setting the cache variable VAR accordingly ac_fn_c_check_func () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Define $2 to an innocuous variant, in case declares $2. For example, HP-UX 11i declares gettimeofday. */ #define $2 innocuous_$2 /* System header to define __stub macros and hopefully few prototypes, which can conflict with char $2 (); below. Prefer to if __STDC__ is defined, since exists even on freestanding compilers. */ #ifdef __STDC__ # include #else # include #endif #undef $2 /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char $2 (); /* The GNU C library defines this for functions which it implements to always fail with ENOSYS. Some functions are actually named something starting with __ and the normal name is an alias. */ #if defined __stub_$2 || defined __stub___$2 choke me #endif int main () { return $2 (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_func # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by bluez $as_me 4.101, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu am__api_version='1.11' ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Just in case sleep 1 echo timestamp > conftest.file # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; esac # Do `set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi rm -f conftest.file if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --run true"; then am_missing_run="$MISSING --run " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using `strip' when the user # run `make install-strip'. However `strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the `STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='bluez' VERSION='4.101' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' ac_config_headers="$ac_config_headers config.h" # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=0;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 $as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } # Check whether --enable-maintainer-mode was given. if test "${enable_maintainer_mode+set}" = set; then : enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval else USE_MAINTAINER_MODE=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 $as_echo "$USE_MAINTAINER_MODE" >&6; } if test $USE_MAINTAINER_MODE = yes; then MAINTAINER_MODE_TRUE= MAINTAINER_MODE_FALSE='#' else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= fi MAINT=$MAINTAINER_MODE_TRUE if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi PKG_CONFIG=$ac_cv_path_PKG_CONFIG if test -n "$PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 $as_echo "$PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_path_PKG_CONFIG"; then ac_pt_PKG_CONFIG=$PKG_CONFIG # Extract the first word of "pkg-config", so it can be a program name with args. set dummy pkg-config; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then : $as_echo_n "(cached) " >&6 else case $ac_pt_PKG_CONFIG in [\\/]* | ?:[\\/]*) ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path. ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS ;; esac fi ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG if test -n "$ac_pt_PKG_CONFIG"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5 $as_echo "$ac_pt_PKG_CONFIG" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_pt_PKG_CONFIG" = x; then PKG_CONFIG="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac PKG_CONFIG=$ac_pt_PKG_CONFIG fi else PKG_CONFIG="$ac_cv_path_PKG_CONFIG" fi fi if test -n "$PKG_CONFIG"; then _pkg_min_version=0.9.0 { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5 $as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; } if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } PKG_CONFIG="" fi fi if (test "${prefix}" = "NONE"); then if (test "$sysconfdir" = '${prefix}/etc'); then sysconfdir='/etc' fi if (test "$localstatedir" = '${prefix}/var'); then localstatedir='/var' fi if (test "$libexecdir" = '${exec_prefix}/libexec'); then libexecdir='/lib' fi if (test "$mandir" = '${prefix}/man'); then mandir='${prefix}/share/man' fi prefix="${ac_default_prefix}" fi if (test "${libdir}" = '${exec_prefix}/lib'); then libdir="${prefix}/lib" fi plugindir="${libdir}/bluetooth/plugins" if (test "$sysconfdir" = '${prefix}/etc'); then configdir="${prefix}/etc/bluetooth" else configdir="${sysconfdir}/bluetooth" fi if (test "$localstatedir" = '${prefix}/var'); then storagedir="${prefix}/var/lib/bluetooth" else storagedir="${localstatedir}/lib/bluetooth" fi cat >>confdefs.h <<_ACEOF #define CONFIGDIR "${configdir}" _ACEOF cat >>confdefs.h <<_ACEOF #define STORAGEDIR "${storagedir}" _ACEOF CONFIGDIR="${configdir}" STORAGEDIR="${storagedir}" UDEV_DIR="`$PKG_CONFIG --variable=udevdir udev`" if (test -z "${UDEV_DIR}"); then UDEV_DIR="/lib/udev" fi with_cflags="" if (test "$USE_MAINTAINER_MODE" = "yes"); then with_cflags="$with_cflags -Wall -Werror -Wextra" with_cflags="$with_cflags -Wno-unused-parameter" with_cflags="$with_cflags -Wno-missing-field-initializers" with_cflags="$with_cflags -Wdeclaration-after-statement" with_cflags="$with_cflags -Wmissing-declarations" with_cflags="$with_cflags -Wredundant-decls" with_cflags="$with_cflags -Wcast-align" with_cflags="$with_cflags -DG_DISABLE_DEPRECATED" fi WARNING_CFLAGS=$with_cflags ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from `make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named `D' -- because `-MD' means `put the output # in D'. rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with # Solaris 8's {/usr,}/bin/sh. touch sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with `-c' and `-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle `-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # after this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok `-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi if test "x$CC" != xcc; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 $as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 $as_echo_n "checking whether cc understands -c and -o together... " >&6; } fi set dummy $CC; ac_cc=`$as_echo "$2" | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` if eval \${ac_cv_prog_cc_${ac_cc}_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # We do the test twice because some compilers refuse to overwrite an # existing .o file with -o, though they will create one. ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -f conftest2.$ac_objext && { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then eval ac_cv_prog_cc_${ac_cc}_c_o=yes if test "x$CC" != xcc; then # Test first that cc exists at all. if { ac_try='cc -c conftest.$ac_ext >&5' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' rm -f conftest2.* if { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -f conftest2.$ac_objext && { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # cc works too. : else # cc exists but doesn't like -o. eval ac_cv_prog_cc_${ac_cc}_c_o=no fi fi fi else eval ac_cv_prog_cc_${ac_cc}_c_o=no fi rm -f core conftest* fi if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h fi # FIXME: we rely on the cache variable name because # there is no other way. set dummy $CC am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o if test "$am_t" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -fPIE" >&5 $as_echo_n "checking whether ${CC-cc} accepts -fPIE... " >&6; } if ${ac_cv_prog_cc_pie+:} false; then : $as_echo_n "(cached) " >&6 else echo 'void f(){}' > conftest.c if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then ac_cv_prog_cc_pie=yes else ac_cv_prog_cc_pie=no fi rm -rf conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_pie" >&5 $as_echo "$ac_cv_prog_cc_pie" >&6; } for ac_prog in 'bison -y' byacc do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_YACC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$YACC"; then ac_cv_prog_YACC="$YACC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_YACC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi YACC=$ac_cv_prog_YACC if test -n "$YACC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 $as_echo "$YACC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$YACC" && break done test -n "$YACC" || YACC="yacc" for ac_prog in flex lex do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LEX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LEX"; then ac_cv_prog_LEX="$LEX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LEX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LEX=$ac_cv_prog_LEX if test -n "$LEX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5 $as_echo "$LEX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$LEX" && break done test -n "$LEX" || LEX=":" if test "x$LEX" != "x:"; then cat >conftest.l <<_ACEOF %% a { ECHO; } b { REJECT; } c { yymore (); } d { yyless (1); } e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */ yyless ((input () != 0)); } f { unput (yytext[0]); } . { BEGIN INITIAL; } %% #ifdef YYTEXT_POINTER extern char *yytext; #endif int main (void) { return ! yylex () + ! yywrap (); } _ACEOF { { ac_try="$LEX conftest.l" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$LEX conftest.l") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5 $as_echo_n "checking lex output file root... " >&6; } if ${ac_cv_prog_lex_root+:} false; then : $as_echo_n "(cached) " >&6 else if test -f lex.yy.c; then ac_cv_prog_lex_root=lex.yy elif test -f lexyy.c; then ac_cv_prog_lex_root=lexyy else as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5 $as_echo "$ac_cv_prog_lex_root" >&6; } LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root if test -z "${LEXLIB+set}"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5 $as_echo_n "checking lex library... " >&6; } if ${ac_cv_lib_lex+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_LIBS=$LIBS ac_cv_lib_lex='none needed' for ac_lib in '' -lfl -ll; do LIBS="$ac_lib $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_lex=$ac_lib fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext test "$ac_cv_lib_lex" != 'none needed' && break done LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5 $as_echo "$ac_cv_lib_lex" >&6; } test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5 $as_echo_n "checking whether yytext is a pointer... " >&6; } if ${ac_cv_prog_lex_yytext_pointer+:} false; then : $as_echo_n "(cached) " >&6 else # POSIX says lex can declare yytext either as a pointer or an array; the # default is implementation-dependent. Figure out which it is, since # not all implementations provide the %pointer and %array declarations. ac_cv_prog_lex_yytext_pointer=no ac_save_LIBS=$LIBS LIBS="$LEXLIB $ac_save_LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #define YYTEXT_POINTER 1 `cat $LEX_OUTPUT_ROOT.c` _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_prog_lex_yytext_pointer=yes fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5 $as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; } if test $ac_cv_prog_lex_yytext_pointer = yes; then $as_echo "#define YYTEXT_POINTER 1" >>confdefs.h fi rm -f conftest.l $LEX_OUTPUT_ROOT.c fi if test "$LEX" = :; then LEX=${am_missing_run}flex fi mkdir_p="$MKDIR_P" case $mkdir_p in [\\/$]* | ?:[\\/]*) ;; */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; esac # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; p=${PACKAGE-default} case $enableval in yes) enable_static=yes ;; no) enable_static=no ;; *) enable_static=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_static=yes fi done IFS="$lt_save_ifs" ;; esac else enable_static=no fi case `pwd` in *\ * | *\ *) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5 $as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;; esac macro_version='2.4.2' macro_revision='1.3337' ltmain="$ac_aux_dir/ltmain.sh" # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac # Backslashify metacharacters that are still active within # double-quoted strings. sed_quote_subst='s/\(["`$\\]\)/\\\1/g' # Same as above, but do not quote variable references. double_quote_subst='s/\(["`\\]\)/\\\1/g' # Sed substitution to delay expansion of an escaped shell variable in a # double_quote_subst'ed string. delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g' # Sed substitution to delay expansion of an escaped single quote. delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g' # Sed substitution to avoid accidental globbing in evaled expressions no_glob_subst='s/\*/\\\*/g' ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5 $as_echo_n "checking how to print strings... " >&6; } # Test print first, because it will be a builtin if present. if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='print -r --' elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then ECHO='printf %s\n' else # Use this function as a fallback that always works. func_fallback_echo () { eval 'cat <<_LTECHO_EOF $1 _LTECHO_EOF' } ECHO='func_fallback_echo' fi # func_echo_all arg... # Invoke $ECHO with all args, space-separated. func_echo_all () { $ECHO "" } case "$ECHO" in printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5 $as_echo "printf" >&6; } ;; print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5 $as_echo "print -r" >&6; } ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5 $as_echo "cat" >&6; } ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5 $as_echo_n "checking for a sed that does not truncate output... " >&6; } if ${ac_cv_path_SED+:} false; then : $as_echo_n "(cached) " >&6 else ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/ for ac_i in 1 2 3 4 5 6 7; do ac_script="$ac_script$as_nl$ac_script" done echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed { ac_script=; unset ac_script;} if test -z "$SED"; then ac_path_SED_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in sed gsed; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_SED="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_SED" || continue # Check for GNU ac_path_SED and select it if it is found. # Check for GNU $ac_path_SED case `"$ac_path_SED" --version 2>&1` in *GNU*) ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo '' >> "conftest.nl" "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_SED_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_SED="$ac_path_SED" ac_path_SED_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_SED_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_SED"; then as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5 fi else ac_cv_path_SED=$SED fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5 $as_echo "$ac_cv_path_SED" >&6; } SED="$ac_cv_path_SED" rm -f conftest.sed test -z "$SED" && SED=sed Xsed="$SED -e 1s/^X//" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5 $as_echo_n "checking for fgrep... " >&6; } if ${ac_cv_path_FGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1 then ac_cv_path_FGREP="$GREP -F" else if test -z "$FGREP"; then ac_path_FGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in fgrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_FGREP" || continue # Check for GNU ac_path_FGREP and select it if it is found. # Check for GNU $ac_path_FGREP case `"$ac_path_FGREP" --version 2>&1` in *GNU*) ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'FGREP' >> "conftest.nl" "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_FGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_FGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_FGREP"; then as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_FGREP=$FGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5 $as_echo "$ac_cv_path_FGREP" >&6; } FGREP="$ac_cv_path_FGREP" test -z "$GREP" && GREP=grep # Check whether --with-gnu-ld was given. if test "${with_gnu_ld+set}" = set; then : withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes else with_gnu_ld=no fi ac_prog=ld if test "$GCC" = yes; then # Check if gcc -print-prog-name=ld gives a path. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5 $as_echo_n "checking for ld used by $CC... " >&6; } case $host in *-*-mingw*) # gcc leaves a trailing carriage return which upsets mingw ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;; *) ac_prog=`($CC -print-prog-name=ld) 2>&5` ;; esac case $ac_prog in # Accept absolute paths. [\\/]* | ?:[\\/]*) re_direlt='/[^/][^/]*/\.\./' # Canonicalize the pathname of ld ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'` while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"` done test -z "$LD" && LD="$ac_prog" ;; "") # If it fails, then pretend we aren't using GCC. ac_prog=ld ;; *) # If it is relative, then search for the first ld in PATH. with_gnu_ld=unknown ;; esac elif test "$with_gnu_ld" = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5 $as_echo_n "checking for GNU ld... " >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5 $as_echo_n "checking for non-GNU ld... " >&6; } fi if ${lt_cv_path_LD+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$LD"; then lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then lt_cv_path_LD="$ac_dir/$ac_prog" # Check to see if the program is GNU ld. I'd rather use --version, # but apparently some variants of GNU ld only accept -v. # Break only if it was the GNU/non-GNU ld that we prefer. case `"$lt_cv_path_LD" -v 2>&1 &5 $as_echo "$LD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5 $as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; } if ${lt_cv_prog_gnu_ld+:} false; then : $as_echo_n "(cached) " >&6 else # I'd rather use --version here, but apparently some GNU lds only accept -v. case `$LD -v 2>&1 &5 $as_echo "$lt_cv_prog_gnu_ld" >&6; } with_gnu_ld=$lt_cv_prog_gnu_ld { $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5 $as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; } if ${lt_cv_path_NM+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NM"; then # Let the user override the test. lt_cv_path_NM="$NM" else lt_nm_to_check="${ac_tool_prefix}nm" if test -n "$ac_tool_prefix" && test "$build" = "$host"; then lt_nm_to_check="$lt_nm_to_check nm" fi for lt_tmp_nm in $lt_nm_to_check; do lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. tmp_nm="$ac_dir/$lt_tmp_nm" if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then # Check to see if the nm accepts a BSD-compat flag. # Adding the `sed 1q' prevents false positives on HP-UX, which says: # nm: unknown option "B" ignored # Tru64's nm complains that /dev/null is an invalid object file case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in */dev/null* | *'Invalid file or object type'*) lt_cv_path_NM="$tmp_nm -B" break ;; *) case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in */dev/null*) lt_cv_path_NM="$tmp_nm -p" break ;; *) lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but continue # so that we can try to find one that supports BSD flags ;; esac ;; esac fi done IFS="$lt_save_ifs" done : ${lt_cv_path_NM=no} fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5 $as_echo "$lt_cv_path_NM" >&6; } if test "$lt_cv_path_NM" != "no"; then NM="$lt_cv_path_NM" else # Didn't find any BSD compatible name lister, look for dumpbin. if test -n "$DUMPBIN"; then : # Let the user override the test. else if test -n "$ac_tool_prefix"; then for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DUMPBIN"; then ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DUMPBIN=$ac_cv_prog_DUMPBIN if test -n "$DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5 $as_echo "$DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$DUMPBIN" && break done fi if test -z "$DUMPBIN"; then ac_ct_DUMPBIN=$DUMPBIN for ac_prog in dumpbin "link -dump" do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DUMPBIN"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DUMPBIN="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN if test -n "$ac_ct_DUMPBIN"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5 $as_echo "$ac_ct_DUMPBIN" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_DUMPBIN" && break done if test "x$ac_ct_DUMPBIN" = x; then DUMPBIN=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DUMPBIN=$ac_ct_DUMPBIN fi fi case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in *COFF*) DUMPBIN="$DUMPBIN -symbols" ;; *) DUMPBIN=: ;; esac fi if test "$DUMPBIN" != ":"; then NM="$DUMPBIN" fi fi test -z "$NM" && NM=nm { $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5 $as_echo_n "checking the name lister ($NM) interface... " >&6; } if ${lt_cv_nm_interface+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_nm_interface="BSD nm" echo "int some_variable = 0;" > conftest.$ac_ext (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5) (eval "$ac_compile" 2>conftest.err) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5) (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out) cat conftest.err >&5 (eval echo "\"\$as_me:$LINENO: output\"" >&5) cat conftest.out >&5 if $GREP 'External.*some_variable' conftest.out > /dev/null; then lt_cv_nm_interface="MS dumpbin" fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5 $as_echo "$lt_cv_nm_interface" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 $as_echo_n "checking whether ln -s works... " >&6; } LN_S=$as_ln_s if test "$LN_S" = "ln -s"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 $as_echo "no, using $LN_S" >&6; } fi # find the maximum length of command line arguments { $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5 $as_echo_n "checking the maximum length of command line arguments... " >&6; } if ${lt_cv_sys_max_cmd_len+:} false; then : $as_echo_n "(cached) " >&6 else i=0 teststring="ABCD" case $build_os in msdosdjgpp*) # On DJGPP, this test can blow up pretty badly due to problems in libc # (any single argument exceeding 2000 bytes causes a buffer overrun # during glob expansion). Even if it were fixed, the result of this # check would be larger than it should be. lt_cv_sys_max_cmd_len=12288; # 12K is about right ;; gnu*) # Under GNU Hurd, this test is not required because there is # no limit to the length of command line arguments. # Libtool will interpret -1 as no limit whatsoever lt_cv_sys_max_cmd_len=-1; ;; cygwin* | mingw* | cegcc*) # On Win9x/ME, this test blows up -- it succeeds, but takes # about 5 minutes as the teststring grows exponentially. # Worse, since 9x/ME are not pre-emptively multitasking, # you end up with a "frozen" computer, even though with patience # the test eventually succeeds (with a max line length of 256k). # Instead, let's just punt: use the minimum linelength reported by # all of the supported platforms: 8192 (on NT/2K/XP). lt_cv_sys_max_cmd_len=8192; ;; mint*) # On MiNT this can take a long time and run out of memory. lt_cv_sys_max_cmd_len=8192; ;; amigaos*) # On AmigaOS with pdksh, this test takes hours, literally. # So we just punt and use a minimum line length of 8192. lt_cv_sys_max_cmd_len=8192; ;; netbsd* | freebsd* | openbsd* | darwin* | dragonfly*) # This has been around since 386BSD, at least. Likely further. if test -x /sbin/sysctl; then lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax` elif test -x /usr/sbin/sysctl; then lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax` else lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs fi # And add a safety zone lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` ;; interix*) # We know the value 262144 and hardcode it with a safety zone (like BSD) lt_cv_sys_max_cmd_len=196608 ;; os2*) # The test takes a long time on OS/2. lt_cv_sys_max_cmd_len=8192 ;; osf*) # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not # nice to cause kernel panics so lets avoid the loop below. # First set a reasonable default. lt_cv_sys_max_cmd_len=16384 # if test -x /sbin/sysconfig; then case `/sbin/sysconfig -q proc exec_disable_arg_limit` in *1*) lt_cv_sys_max_cmd_len=-1 ;; esac fi ;; sco3.2v5*) lt_cv_sys_max_cmd_len=102400 ;; sysv5* | sco5v6* | sysv4.2uw2*) kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null` if test -n "$kargmax"; then lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'` else lt_cv_sys_max_cmd_len=32768 fi ;; *) lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null` if test -n "$lt_cv_sys_max_cmd_len"; then lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4` lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3` else # Make teststring a little bigger before we do anything with it. # a 1K string should be a reasonable start. for i in 1 2 3 4 5 6 7 8 ; do teststring=$teststring$teststring done SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}} # If test is not a shell built-in, we'll probably end up computing a # maximum length that is only half of the actual maximum length, but # we can't tell. while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \ = "X$teststring$teststring"; } >/dev/null 2>&1 && test $i != 17 # 1/2 MB should be enough do i=`expr $i + 1` teststring=$teststring$teststring done # Only check the string length outside the loop. lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1` teststring= # Add a significant safety factor because C++ compilers can tack on # massive amounts of additional arguments before passing them to the # linker. It appears as though 1/2 is a usable value. lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2` fi ;; esac fi if test -n $lt_cv_sys_max_cmd_len ; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5 $as_echo "$lt_cv_sys_max_cmd_len" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5 $as_echo "none" >&6; } fi max_cmd_len=$lt_cv_sys_max_cmd_len : ${CP="cp -f"} : ${MV="mv -f"} : ${RM="rm -f"} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5 $as_echo_n "checking whether the shell understands some XSI constructs... " >&6; } # Try some XSI features xsi_shell=no ( _lt_dummy="a/b/c" test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \ = c,a/b,b/c, \ && eval 'test $(( 1 + 1 )) -eq 2 \ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \ && xsi_shell=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5 $as_echo "$xsi_shell" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5 $as_echo_n "checking whether the shell understands \"+=\"... " >&6; } lt_shell_append=no ( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \ >/dev/null 2>&1 \ && lt_shell_append=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5 $as_echo "$lt_shell_append" >&6; } if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then lt_unset=unset else lt_unset=false fi # test EBCDIC or ASCII case `echo X|tr X '\101'` in A) # ASCII based system # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr lt_SP2NL='tr \040 \012' lt_NL2SP='tr \015\012 \040\040' ;; *) # EBCDIC based system lt_SP2NL='tr \100 \n' lt_NL2SP='tr \r\n \100\100' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5 $as_echo_n "checking how to convert $build file names to $host format... " >&6; } if ${lt_cv_to_host_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32 ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32 ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32 ;; esac ;; *-*-cygwin* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin ;; *-*-cygwin* ) lt_cv_to_host_file_cmd=func_convert_file_noop ;; * ) # otherwise, assume *nix lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin ;; esac ;; * ) # unhandled hosts (and "normal" native builds) lt_cv_to_host_file_cmd=func_convert_file_noop ;; esac fi to_host_file_cmd=$lt_cv_to_host_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5 $as_echo "$lt_cv_to_host_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5 $as_echo_n "checking how to convert $build file names to toolchain format... " >&6; } if ${lt_cv_to_tool_file_cmd+:} false; then : $as_echo_n "(cached) " >&6 else #assume ordinary cross tools, or native build. lt_cv_to_tool_file_cmd=func_convert_file_noop case $host in *-*-mingw* ) case $build in *-*-mingw* ) # actually msys lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32 ;; esac ;; esac fi to_tool_file_cmd=$lt_cv_to_tool_file_cmd { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5 $as_echo "$lt_cv_to_tool_file_cmd" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5 $as_echo_n "checking for $LD option to reload object files... " >&6; } if ${lt_cv_ld_reload_flag+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_reload_flag='-r' fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5 $as_echo "$lt_cv_ld_reload_flag" >&6; } reload_flag=$lt_cv_ld_reload_flag case $reload_flag in "" | " "*) ;; *) reload_flag=" $reload_flag" ;; esac reload_cmds='$LD$reload_flag -o $output$reload_objs' case $host_os in cygwin* | mingw* | pw32* | cegcc*) if test "$GCC" != yes; then reload_cmds=false fi ;; darwin*) if test "$GCC" = yes; then reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs' else reload_cmds='$LD$reload_flag -o $output$reload_objs' fi ;; esac if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args. set dummy ${ac_tool_prefix}objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OBJDUMP"; then ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OBJDUMP=$ac_cv_prog_OBJDUMP if test -n "$OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5 $as_echo "$OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OBJDUMP"; then ac_ct_OBJDUMP=$OBJDUMP # Extract the first word of "objdump", so it can be a program name with args. set dummy objdump; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OBJDUMP"; then ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OBJDUMP="objdump" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP if test -n "$ac_ct_OBJDUMP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5 $as_echo "$ac_ct_OBJDUMP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OBJDUMP" = x; then OBJDUMP="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OBJDUMP=$ac_ct_OBJDUMP fi else OBJDUMP="$ac_cv_prog_OBJDUMP" fi test -z "$OBJDUMP" && OBJDUMP=objdump { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5 $as_echo_n "checking how to recognize dependent libraries... " >&6; } if ${lt_cv_deplibs_check_method+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_file_magic_cmd='$MAGIC_CMD' lt_cv_file_magic_test_file= lt_cv_deplibs_check_method='unknown' # Need to set the preceding variable on all platforms that support # interlibrary dependencies. # 'none' -- dependencies not supported. # `unknown' -- same as none, but documents that we really don't know. # 'pass_all' -- all dependencies passed with no checks. # 'test_compile' -- check by making test program. # 'file_magic [[regex]]' -- check by looking for files in library path # which responds to the $file_magic_cmd with a given extended regex. # If you have `file' or equivalent on your system and you're not sure # whether `pass_all' will *always* work, you probably want this one. case $host_os in aix[4-9]*) lt_cv_deplibs_check_method=pass_all ;; beos*) lt_cv_deplibs_check_method=pass_all ;; bsdi[45]*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)' lt_cv_file_magic_cmd='/usr/bin/file -L' lt_cv_file_magic_test_file=/shlib/libc.so ;; cygwin*) # func_win32_libid is a shell function defined in ltmain.sh lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' ;; mingw* | pw32*) # Base MSYS/MinGW do not provide the 'file' command needed by # func_win32_libid shell function, so use a weaker test based on 'objdump', # unless we find 'file', for example because we are cross-compiling. # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin. if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL' lt_cv_file_magic_cmd='func_win32_libid' else # Keep this pattern in sync with the one in func_win32_libid. lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' lt_cv_file_magic_cmd='$OBJDUMP -f' fi ;; cegcc*) # use the weaker test based on 'objdump'. See mingw*. lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?' lt_cv_file_magic_cmd='$OBJDUMP -f' ;; darwin* | rhapsody*) lt_cv_deplibs_check_method=pass_all ;; freebsd* | dragonfly*) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then case $host_cpu in i*86 ) # Not sure whether the presence of OpenBSD here was a mistake. # Let's accept both of them until this is cleared up. lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*` ;; esac else lt_cv_deplibs_check_method=pass_all fi ;; gnu*) lt_cv_deplibs_check_method=pass_all ;; haiku*) lt_cv_deplibs_check_method=pass_all ;; hpux10.20* | hpux11*) lt_cv_file_magic_cmd=/usr/bin/file case $host_cpu in ia64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64' lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so ;; hppa*64*) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]' lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl ;; *) lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library' lt_cv_file_magic_test_file=/usr/lib/libc.sl ;; esac ;; interix[3-9]*) # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$' ;; irix5* | irix6* | nonstopux*) case $LD in *-32|*"-32 ") libmagic=32-bit;; *-n32|*"-n32 ") libmagic=N32;; *-64|*"-64 ") libmagic=64-bit;; *) libmagic=never-match;; esac lt_cv_deplibs_check_method=pass_all ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) lt_cv_deplibs_check_method=pass_all ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$' fi ;; newos6*) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)' lt_cv_file_magic_cmd=/usr/bin/file lt_cv_file_magic_test_file=/usr/lib/libnls.so ;; *nto* | *qnx*) lt_cv_deplibs_check_method=pass_all ;; openbsd*) if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$' else lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$' fi ;; osf3* | osf4* | osf5*) lt_cv_deplibs_check_method=pass_all ;; rdos*) lt_cv_deplibs_check_method=pass_all ;; solaris*) lt_cv_deplibs_check_method=pass_all ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) lt_cv_deplibs_check_method=pass_all ;; sysv4 | sysv4.3*) case $host_vendor in motorola) lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]' lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*` ;; ncr) lt_cv_deplibs_check_method=pass_all ;; sequent) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )' ;; sni) lt_cv_file_magic_cmd='/bin/file' lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib" lt_cv_file_magic_test_file=/lib/libc.so ;; siemens) lt_cv_deplibs_check_method=pass_all ;; pc) lt_cv_deplibs_check_method=pass_all ;; esac ;; tpf*) lt_cv_deplibs_check_method=pass_all ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5 $as_echo "$lt_cv_deplibs_check_method" >&6; } file_magic_glob= want_nocaseglob=no if test "$build" = "$host"; then case $host_os in mingw* | pw32*) if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then want_nocaseglob=yes else file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"` fi ;; esac fi file_magic_cmd=$lt_cv_file_magic_cmd deplibs_check_method=$lt_cv_deplibs_check_method test -z "$deplibs_check_method" && deplibs_check_method=unknown if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args. set dummy ${ac_tool_prefix}dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DLLTOOL"; then ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DLLTOOL=$ac_cv_prog_DLLTOOL if test -n "$DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5 $as_echo "$DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DLLTOOL"; then ac_ct_DLLTOOL=$DLLTOOL # Extract the first word of "dlltool", so it can be a program name with args. set dummy dlltool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DLLTOOL"; then ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DLLTOOL="dlltool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL if test -n "$ac_ct_DLLTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5 $as_echo "$ac_ct_DLLTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DLLTOOL" = x; then DLLTOOL="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DLLTOOL=$ac_ct_DLLTOOL fi else DLLTOOL="$ac_cv_prog_DLLTOOL" fi test -z "$DLLTOOL" && DLLTOOL=dlltool { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5 $as_echo_n "checking how to associate runtime and link libraries... " >&6; } if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_sharedlib_from_linklib_cmd='unknown' case $host_os in cygwin* | mingw* | pw32* | cegcc*) # two different shell functions defined in ltmain.sh # decide which to use based on capabilities of $DLLTOOL case `$DLLTOOL --help 2>&1` in *--identify-strict*) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib ;; *) lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback ;; esac ;; *) # fallback: assume linklib IS sharedlib lt_cv_sharedlib_from_linklib_cmd="$ECHO" ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5 $as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; } sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO if test -n "$ac_tool_prefix"; then for ac_prog in ar do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AR"; then ac_cv_prog_AR="$AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AR=$ac_cv_prog_AR if test -n "$AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5 $as_echo "$AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AR" && break done fi if test -z "$AR"; then ac_ct_AR=$AR for ac_prog in ar do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_AR+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_AR"; then ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_AR="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_AR=$ac_cv_prog_ac_ct_AR if test -n "$ac_ct_AR"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5 $as_echo "$ac_ct_AR" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_AR" && break done if test "x$ac_ct_AR" = x; then AR="false" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac AR=$ac_ct_AR fi fi : ${AR=ar} : ${AR_FLAGS=cru} { $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5 $as_echo_n "checking for archiver @FILE support... " >&6; } if ${lt_cv_ar_at_file+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ar_at_file=no cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : echo conftest.$ac_objext > conftest.lst lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5' { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -eq 0; then # Ensure the archiver fails upon bogus file names. rm -f conftest.$ac_objext libconftest.a { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5 (eval $lt_ar_try) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if test "$ac_status" -ne 0; then lt_cv_ar_at_file=@ fi fi rm -f conftest.* libconftest.a fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5 $as_echo "$lt_cv_ar_at_file" >&6; } if test "x$lt_cv_ar_at_file" = xno; then archiver_list_spec= else archiver_list_spec=$lt_cv_ar_at_file fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi test -z "$STRIP" && STRIP=: if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. set dummy ${ac_tool_prefix}ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$RANLIB"; then ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi RANLIB=$ac_cv_prog_RANLIB if test -n "$RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 $as_echo "$RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_RANLIB"; then ac_ct_RANLIB=$RANLIB # Extract the first word of "ranlib", so it can be a program name with args. set dummy ranlib; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_RANLIB+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_RANLIB"; then ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB if test -n "$ac_ct_RANLIB"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 $as_echo "$ac_ct_RANLIB" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_RANLIB" = x; then RANLIB=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac RANLIB=$ac_ct_RANLIB fi else RANLIB="$ac_cv_prog_RANLIB" fi test -z "$RANLIB" && RANLIB=: # Determine commands to create old-style static archives. old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs' old_postinstall_cmds='chmod 644 $oldlib' old_postuninstall_cmds= if test -n "$RANLIB"; then case $host_os in openbsd*) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib" ;; *) old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib" ;; esac old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib" fi case $host_os in darwin*) lock_old_archive_extraction=yes ;; *) lock_old_archive_extraction=no ;; esac # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Check for command to grab the raw symbol name followed by C symbol from nm. { $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5 $as_echo_n "checking command to parse $NM output from $compiler object... " >&6; } if ${lt_cv_sys_global_symbol_pipe+:} false; then : $as_echo_n "(cached) " >&6 else # These are sane defaults that work on at least a few old systems. # [They come from Ultrix. What could be older than Ultrix?!! ;)] # Character class describing NM global symbol codes. symcode='[BCDEGRST]' # Regexp to match symbols that can be accessed directly from C. sympat='\([_A-Za-z][_A-Za-z0-9]*\)' # Define system-specific variables. case $host_os in aix*) symcode='[BCDT]' ;; cygwin* | mingw* | pw32* | cegcc*) symcode='[ABCDGISTW]' ;; hpux*) if test "$host_cpu" = ia64; then symcode='[ABCDEGRST]' fi ;; irix* | nonstopux*) symcode='[BCDEGRST]' ;; osf*) symcode='[BCDEGQRST]' ;; solaris*) symcode='[BDRT]' ;; sco3.2v5*) symcode='[DT]' ;; sysv4.2uw2*) symcode='[DT]' ;; sysv5* | sco5v6* | unixware* | OpenUNIX*) symcode='[ABDT]' ;; sysv4) symcode='[DFNSTU]' ;; esac # If we're using GNU nm, then use its standard symbol codes. case `$NM -V 2>&1` in *GNU* | *'with BFD'*) symcode='[ABCDGIRSTW]' ;; esac # Transform an extracted symbol line into a proper C declaration. # Some systems (esp. on ia64) link data and code symbols differently, # so use this general approach. lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'" # Transform an extracted symbol line into symbol name and symbol address lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'" lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'" # Handle CRLF in mingw tool chain opt_cr= case $build_os in mingw*) opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp ;; esac # Try without a prefix underscore, then with it. for ac_symprfx in "" "_"; do # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol. symxfrm="\\1 $ac_symprfx\\2 \\2" # Write the raw and C identifiers. if test "$lt_cv_nm_interface" = "MS dumpbin"; then # Fake it for dumpbin and say T for any non-static function # and D for any global variable. # Also find C++ and __fastcall symbols from MSVC++, # which start with @ or ?. lt_cv_sys_global_symbol_pipe="$AWK '"\ " {last_section=section; section=\$ 3};"\ " /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\ " /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\ " \$ 0!~/External *\|/{next};"\ " / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\ " {if(hide[section]) next};"\ " {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\ " {split(\$ 0, a, /\||\r/); split(a[2], s)};"\ " s[1]~/^[@?]/{print s[1], s[1]; next};"\ " s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\ " ' prfx=^$ac_symprfx" else lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'" fi lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'" # Check to see that the pipe works correctly. pipe_works=no rm -f conftest* cat > conftest.$ac_ext <<_LT_EOF #ifdef __cplusplus extern "C" { #endif char nm_test_var; void nm_test_func(void); void nm_test_func(void){} #ifdef __cplusplus } #endif int main(){nm_test_var='a';nm_test_func();return(0);} _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then # Now try to grab the symbols. nlist=conftest.nm if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5 (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s "$nlist"; then # Try sorting and uniquifying the output. if sort "$nlist" | uniq > "$nlist"T; then mv -f "$nlist"T "$nlist" else rm -f "$nlist"T fi # Make sure that we snagged all the symbols we need. if $GREP ' nm_test_var$' "$nlist" >/dev/null; then if $GREP ' nm_test_func$' "$nlist" >/dev/null; then cat <<_LT_EOF > conftest.$ac_ext /* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */ #if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE) /* DATA imports from DLLs on WIN32 con't be const, because runtime relocations are performed -- see ld's documentation on pseudo-relocs. */ # define LT_DLSYM_CONST #elif defined(__osf__) /* This system does not cope well with relocations in const data. */ # define LT_DLSYM_CONST #else # define LT_DLSYM_CONST const #endif #ifdef __cplusplus extern "C" { #endif _LT_EOF # Now generate the symbol file. eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext' cat <<_LT_EOF >> conftest.$ac_ext /* The mapping between symbol names and symbols. */ LT_DLSYM_CONST struct { const char *name; void *address; } lt__PROGRAM__LTX_preloaded_symbols[] = { { "@PROGRAM@", (void *) 0 }, _LT_EOF $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext cat <<\_LT_EOF >> conftest.$ac_ext {0, (void *) 0} }; /* This works around a problem in FreeBSD linker */ #ifdef FREEBSD_WORKAROUND static const void *lt_preloaded_setup() { return lt__PROGRAM__LTX_preloaded_symbols; } #endif #ifdef __cplusplus } #endif _LT_EOF # Now try linking the two files. mv conftest.$ac_objext conftstm.$ac_objext lt_globsym_save_LIBS=$LIBS lt_globsym_save_CFLAGS=$CFLAGS LIBS="conftstm.$ac_objext" CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag" if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext}; then pipe_works=yes fi LIBS=$lt_globsym_save_LIBS CFLAGS=$lt_globsym_save_CFLAGS else echo "cannot find nm_test_func in $nlist" >&5 fi else echo "cannot find nm_test_var in $nlist" >&5 fi else echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5 fi else echo "$progname: failed program was:" >&5 cat conftest.$ac_ext >&5 fi rm -rf conftest* conftst* # Do not use the global_symbol_pipe unless it works. if test "$pipe_works" = yes; then break else lt_cv_sys_global_symbol_pipe= fi done fi if test -z "$lt_cv_sys_global_symbol_pipe"; then lt_cv_sys_global_symbol_to_cdecl= fi if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5 $as_echo "failed" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5 $as_echo "ok" >&6; } fi # Response file support. if test "$lt_cv_nm_interface" = "MS dumpbin"; then nm_file_list_spec='@' elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then nm_file_list_spec='@' fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5 $as_echo_n "checking for sysroot... " >&6; } # Check whether --with-sysroot was given. if test "${with_sysroot+set}" = set; then : withval=$with_sysroot; else with_sysroot=no fi lt_sysroot= case ${with_sysroot} in #( yes) if test "$GCC" = yes; then lt_sysroot=`$CC --print-sysroot 2>/dev/null` fi ;; #( /*) lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"` ;; #( no|'') ;; #( *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5 $as_echo "${with_sysroot}" >&6; } as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5 $as_echo "${lt_sysroot:-no}" >&6; } # Check whether --enable-libtool-lock was given. if test "${enable_libtool_lock+set}" = set; then : enableval=$enable_libtool_lock; fi test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes # Some flags need to be propagated to the compiler or linker for good # libtool support. case $host in ia64-*-hpux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.$ac_objext` in *ELF-32*) HPUX_IA64_MODE="32" ;; *ELF-64*) HPUX_IA64_MODE="64" ;; esac fi rm -rf conftest* ;; *-*-irix6*) # Find out which ABI we are using. echo '#line '$LINENO' "configure"' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then if test "$lt_cv_prog_gnu_ld" = yes; then case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -melf32bsmip" ;; *N32*) LD="${LD-ld} -melf32bmipn32" ;; *64-bit*) LD="${LD-ld} -melf64bmip" ;; esac else case `/usr/bin/file conftest.$ac_objext` in *32-bit*) LD="${LD-ld} -32" ;; *N32*) LD="${LD-ld} -n32" ;; *64-bit*) LD="${LD-ld} -64" ;; esac fi fi rm -rf conftest* ;; x86_64-*kfreebsd*-gnu|x86_64-*linux*|ppc*-*linux*|powerpc*-*linux*| \ s390*-*linux*|s390*-*tpf*|sparc*-*linux*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *32-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_i386_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_i386" ;; ppc64-*linux*|powerpc64-*linux*) LD="${LD-ld} -m elf32ppclinux" ;; s390x-*linux*) LD="${LD-ld} -m elf_s390" ;; sparc64-*linux*) LD="${LD-ld} -m elf32_sparc" ;; esac ;; *64-bit*) case $host in x86_64-*kfreebsd*-gnu) LD="${LD-ld} -m elf_x86_64_fbsd" ;; x86_64-*linux*) LD="${LD-ld} -m elf_x86_64" ;; ppc*-*linux*|powerpc*-*linux*) LD="${LD-ld} -m elf64ppc" ;; s390*-*linux*|s390*-*tpf*) LD="${LD-ld} -m elf64_s390" ;; sparc*-*linux*) LD="${LD-ld} -m elf64_sparc" ;; esac ;; esac fi rm -rf conftest* ;; *-*-sco3.2v5*) # On SCO OpenServer 5, we need -belf to get full-featured binaries. SAVE_CFLAGS="$CFLAGS" CFLAGS="$CFLAGS -belf" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5 $as_echo_n "checking whether the C compiler needs -belf... " >&6; } if ${lt_cv_cc_needs_belf+:} false; then : $as_echo_n "(cached) " >&6 else ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_cc_needs_belf=yes else lt_cv_cc_needs_belf=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5 $as_echo "$lt_cv_cc_needs_belf" >&6; } if test x"$lt_cv_cc_needs_belf" != x"yes"; then # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf CFLAGS="$SAVE_CFLAGS" fi ;; *-*solaris*) # Find out which ABI we are using. echo 'int i;' > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then case `/usr/bin/file conftest.o` in *64-bit*) case $lt_cv_prog_gnu_ld in yes*) case $host in i?86-*-solaris*) LD="${LD-ld} -m elf_x86_64" ;; sparc*-*-solaris*) LD="${LD-ld} -m elf64_sparc" ;; esac # GNU ld 2.21 introduced _sol2 emulations. Use them if available. if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then LD="${LD-ld}_sol2" fi ;; *) if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then LD="${LD-ld} -64" fi ;; esac ;; esac fi rm -rf conftest* ;; esac need_locks="$enable_libtool_lock" if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args. set dummy ${ac_tool_prefix}mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$MANIFEST_TOOL"; then ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL if test -n "$MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5 $as_echo "$MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_MANIFEST_TOOL"; then ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL # Extract the first word of "mt", so it can be a program name with args. set dummy mt; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_MANIFEST_TOOL"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_MANIFEST_TOOL="mt" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL if test -n "$ac_ct_MANIFEST_TOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5 $as_echo "$ac_ct_MANIFEST_TOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_MANIFEST_TOOL" = x; then MANIFEST_TOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL fi else MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL" fi test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5 $as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; } if ${lt_cv_path_mainfest_tool+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_path_mainfest_tool=no echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5 $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out cat conftest.err >&5 if $GREP 'Manifest Tool' conftest.out > /dev/null; then lt_cv_path_mainfest_tool=yes fi rm -f conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5 $as_echo "$lt_cv_path_mainfest_tool" >&6; } if test "x$lt_cv_path_mainfest_tool" != xyes; then MANIFEST_TOOL=: fi case $host_os in rhapsody* | darwin*) if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args. set dummy ${ac_tool_prefix}dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$DSYMUTIL"; then ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi DSYMUTIL=$ac_cv_prog_DSYMUTIL if test -n "$DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5 $as_echo "$DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_DSYMUTIL"; then ac_ct_DSYMUTIL=$DSYMUTIL # Extract the first word of "dsymutil", so it can be a program name with args. set dummy dsymutil; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_DSYMUTIL"; then ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_DSYMUTIL="dsymutil" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL if test -n "$ac_ct_DSYMUTIL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5 $as_echo "$ac_ct_DSYMUTIL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_DSYMUTIL" = x; then DSYMUTIL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac DSYMUTIL=$ac_ct_DSYMUTIL fi else DSYMUTIL="$ac_cv_prog_DSYMUTIL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args. set dummy ${ac_tool_prefix}nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$NMEDIT"; then ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi NMEDIT=$ac_cv_prog_NMEDIT if test -n "$NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5 $as_echo "$NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_NMEDIT"; then ac_ct_NMEDIT=$NMEDIT # Extract the first word of "nmedit", so it can be a program name with args. set dummy nmedit; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_NMEDIT"; then ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_NMEDIT="nmedit" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT if test -n "$ac_ct_NMEDIT"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5 $as_echo "$ac_ct_NMEDIT" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_NMEDIT" = x; then NMEDIT=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac NMEDIT=$ac_ct_NMEDIT fi else NMEDIT="$ac_cv_prog_NMEDIT" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args. set dummy ${ac_tool_prefix}lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$LIPO"; then ac_cv_prog_LIPO="$LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_LIPO="${ac_tool_prefix}lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi LIPO=$ac_cv_prog_LIPO if test -n "$LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5 $as_echo "$LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_LIPO"; then ac_ct_LIPO=$LIPO # Extract the first word of "lipo", so it can be a program name with args. set dummy lipo; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_LIPO+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_LIPO"; then ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_LIPO="lipo" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO if test -n "$ac_ct_LIPO"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5 $as_echo "$ac_ct_LIPO" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_LIPO" = x; then LIPO=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac LIPO=$ac_ct_LIPO fi else LIPO="$ac_cv_prog_LIPO" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args. set dummy ${ac_tool_prefix}otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL"; then ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL="${ac_tool_prefix}otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL=$ac_cv_prog_OTOOL if test -n "$OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5 $as_echo "$OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL"; then ac_ct_OTOOL=$OTOOL # Extract the first word of "otool", so it can be a program name with args. set dummy otool; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL"; then ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL="otool" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL if test -n "$ac_ct_OTOOL"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5 $as_echo "$ac_ct_OTOOL" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL" = x; then OTOOL=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL=$ac_ct_OTOOL fi else OTOOL="$ac_cv_prog_OTOOL" fi if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args. set dummy ${ac_tool_prefix}otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$OTOOL64"; then ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi OTOOL64=$ac_cv_prog_OTOOL64 if test -n "$OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5 $as_echo "$OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_OTOOL64"; then ac_ct_OTOOL64=$OTOOL64 # Extract the first word of "otool64", so it can be a program name with args. set dummy otool64; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_OTOOL64"; then ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_OTOOL64="otool64" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64 if test -n "$ac_ct_OTOOL64"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5 $as_echo "$ac_ct_OTOOL64" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_OTOOL64" = x; then OTOOL64=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac OTOOL64=$ac_ct_OTOOL64 fi else OTOOL64="$ac_cv_prog_OTOOL64" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5 $as_echo_n "checking for -single_module linker flag... " >&6; } if ${lt_cv_apple_cc_single_mod+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_apple_cc_single_mod=no if test -z "${LT_MULTI_MODULE}"; then # By default we will add the -single_module flag. You can override # by either setting the environment variable LT_MULTI_MODULE # non-empty at configure time, or by adding -multi_module to the # link flags. rm -rf libconftest.dylib* echo "int foo(void){return 1;}" > conftest.c echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c" >&5 $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err _lt_result=$? # If there is a non-empty error log, and "single_module" # appears in it, assume the flag caused a linker warning if test -s conftest.err && $GREP single_module conftest.err; then cat conftest.err >&5 # Otherwise, if the output was created with a 0 exit code from # the compiler, it worked. elif test -f libconftest.dylib && test $_lt_result -eq 0; then lt_cv_apple_cc_single_mod=yes else cat conftest.err >&5 fi rm -rf libconftest.dylib* rm -f conftest.* fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5 $as_echo "$lt_cv_apple_cc_single_mod" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5 $as_echo_n "checking for -exported_symbols_list linker flag... " >&6; } if ${lt_cv_ld_exported_symbols_list+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_exported_symbols_list=no save_LDFLAGS=$LDFLAGS echo "_main" > conftest.sym LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_ld_exported_symbols_list=yes else lt_cv_ld_exported_symbols_list=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5 $as_echo "$lt_cv_ld_exported_symbols_list" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5 $as_echo_n "checking for -force_load linker flag... " >&6; } if ${lt_cv_ld_force_load+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_ld_force_load=no cat > conftest.c << _LT_EOF int forced_loaded() { return 2;} _LT_EOF echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5 $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5 echo "$AR cru libconftest.a conftest.o" >&5 $AR cru libconftest.a conftest.o 2>&5 echo "$RANLIB libconftest.a" >&5 $RANLIB libconftest.a 2>&5 cat > conftest.c << _LT_EOF int main() { return 0;} _LT_EOF echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5 $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err _lt_result=$? if test -s conftest.err && $GREP force_load conftest.err; then cat conftest.err >&5 elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then lt_cv_ld_force_load=yes else cat conftest.err >&5 fi rm -f conftest.err libconftest.a conftest conftest.c rm -rf conftest.dSYM fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5 $as_echo "$lt_cv_ld_force_load" >&6; } case $host_os in rhapsody* | darwin1.[012]) _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;; darwin1.*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; darwin*) # darwin 5.x on # if running on 10.5 or later, the deployment target defaults # to the OS version, if on x86, and 10.4, the deployment # target defaults to 10.4. Don't you love it? case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in 10.0,*86*-darwin8*|10.0,*-darwin[91]*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; 10.[012]*) _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;; 10.*) _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;; esac ;; esac if test "$lt_cv_apple_cc_single_mod" = "yes"; then _lt_dar_single_mod='$single_module' fi if test "$lt_cv_ld_exported_symbols_list" = "yes"; then _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym' else _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}' fi if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then _lt_dsymutil='~$DSYMUTIL $lib || :' else _lt_dsymutil= fi ;; esac ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done for ac_header in dlfcn.h do : ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default " if test "x$ac_cv_header_dlfcn_h" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_DLFCN_H 1 _ACEOF fi done # Set options enable_dlopen=no enable_win32_dll=no # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; p=${PACKAGE-default} case $enableval in yes) enable_shared=yes ;; no) enable_shared=no ;; *) enable_shared=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_shared=yes fi done IFS="$lt_save_ifs" ;; esac else enable_shared=yes fi # Check whether --with-pic was given. if test "${with_pic+set}" = set; then : withval=$with_pic; lt_p=${PACKAGE-default} case $withval in yes|no) pic_mode=$withval ;; *) pic_mode=default # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for lt_pkg in $withval; do IFS="$lt_save_ifs" if test "X$lt_pkg" = "X$lt_p"; then pic_mode=yes fi done IFS="$lt_save_ifs" ;; esac else pic_mode=default fi test -z "$pic_mode" && pic_mode=default # Check whether --enable-fast-install was given. if test "${enable_fast_install+set}" = set; then : enableval=$enable_fast_install; p=${PACKAGE-default} case $enableval in yes) enable_fast_install=yes ;; no) enable_fast_install=no ;; *) enable_fast_install=no # Look at the argument we got. We use all the common list separators. lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR," for pkg in $enableval; do IFS="$lt_save_ifs" if test "X$pkg" = "X$p"; then enable_fast_install=yes fi done IFS="$lt_save_ifs" ;; esac else enable_fast_install=yes fi # This can be used to rebuild libtool when needed LIBTOOL_DEPS="$ltmain" # Always use our own libtool. LIBTOOL='$(SHELL) $(top_builddir)/libtool' test -z "$LN_S" && LN_S="ln -s" if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5 $as_echo_n "checking for objdir... " >&6; } if ${lt_cv_objdir+:} false; then : $as_echo_n "(cached) " >&6 else rm -f .libs 2>/dev/null mkdir .libs 2>/dev/null if test -d .libs; then lt_cv_objdir=.libs else # MS-DOS does not allow filenames that begin with a dot. lt_cv_objdir=_libs fi rmdir .libs 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5 $as_echo "$lt_cv_objdir" >&6; } objdir=$lt_cv_objdir cat >>confdefs.h <<_ACEOF #define LT_OBJDIR "$lt_cv_objdir/" _ACEOF case $host_os in aix3*) # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi ;; esac # Global variables: ofile=libtool can_build_shared=yes # All known linkers require a `.a' archive for static linking (except MSVC, # which needs '.lib'). libext=a with_gnu_ld="$lt_cv_prog_gnu_ld" old_CC="$CC" old_CFLAGS="$CFLAGS" # Set sane defaults for various variables test -z "$CC" && CC=cc test -z "$LTCC" && LTCC=$CC test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS test -z "$LD" && LD=ld test -z "$ac_objext" && ac_objext=o for cc_temp in $compiler""; do case $cc_temp in compile | *[\\/]compile | ccache | *[\\/]ccache ) ;; distcc | *[\\/]distcc | purify | *[\\/]purify ) ;; \-*) ;; *) break;; esac done cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"` # Only perform the check for file, if the check method requires it test -z "$MAGIC_CMD" && MAGIC_CMD=file case $deplibs_check_method in file_magic*) if test "$file_magic_cmd" = '$MAGIC_CMD'; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5 $as_echo_n "checking for ${ac_tool_prefix}file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/${ac_tool_prefix}file; then lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test -z "$lt_cv_path_MAGIC_CMD"; then if test -n "$ac_tool_prefix"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5 $as_echo_n "checking for file... " >&6; } if ${lt_cv_path_MAGIC_CMD+:} false; then : $as_echo_n "(cached) " >&6 else case $MAGIC_CMD in [\\/*] | ?:[\\/]*) lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path. ;; *) lt_save_MAGIC_CMD="$MAGIC_CMD" lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR ac_dummy="/usr/bin$PATH_SEPARATOR$PATH" for ac_dir in $ac_dummy; do IFS="$lt_save_ifs" test -z "$ac_dir" && ac_dir=. if test -f $ac_dir/file; then lt_cv_path_MAGIC_CMD="$ac_dir/file" if test -n "$file_magic_test_file"; then case $deplibs_check_method in "file_magic "*) file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"` MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null | $EGREP "$file_magic_regex" > /dev/null; then : else cat <<_LT_EOF 1>&2 *** Warning: the command libtool uses to detect shared libraries, *** $file_magic_cmd, produces output that libtool cannot recognize. *** The result is that libtool may fail to recognize shared libraries *** as such. This will affect the creation of libtool libraries that *** depend on shared libraries, but programs linked with such libtool *** libraries will work regardless of this problem. Nevertheless, you *** may want to report the problem to your system manager and/or to *** bug-libtool@gnu.org _LT_EOF fi ;; esac fi break fi done IFS="$lt_save_ifs" MAGIC_CMD="$lt_save_MAGIC_CMD" ;; esac fi MAGIC_CMD="$lt_cv_path_MAGIC_CMD" if test -n "$MAGIC_CMD"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5 $as_echo "$MAGIC_CMD" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi else MAGIC_CMD=: fi fi fi ;; esac # Use C for the default configuration in the libtool script lt_save_CC="$CC" ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Source file extension for C test sources. ac_ext=c # Object file extension for compiled C test sources. objext=o objext=$objext # Code to be used in simple compile tests lt_simple_compile_test_code="int some_variable = 0;" # Code to be used in simple link tests lt_simple_link_test_code='int main(){return(0);}' # If no C compiler was specified, use CC. LTCC=${LTCC-"$CC"} # If no C compiler flags were specified, use CFLAGS. LTCFLAGS=${LTCFLAGS-"$CFLAGS"} # Allow CC to be a program name with arguments. compiler=$CC # Save the default compiler, since it gets overwritten when the other # tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP. compiler_DEFAULT=$CC # save warnings/boilerplate of simple test code ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" >conftest.$ac_ext eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_compiler_boilerplate=`cat conftest.err` $RM conftest* ac_outfile=conftest.$ac_objext echo "$lt_simple_link_test_code" >conftest.$ac_ext eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err _lt_linker_boilerplate=`cat conftest.err` $RM -r conftest* if test -n "$compiler"; then lt_prog_compiler_no_builtin_flag= if test "$GCC" = yes; then case $cc_basename in nvcc*) lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;; *) lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5 $as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; } if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_rtti_exceptions=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-fno-rtti -fno-exceptions" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_rtti_exceptions=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5 $as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; } if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions" else : fi fi lt_prog_compiler_wl= lt_prog_compiler_pic= lt_prog_compiler_static= if test "$GCC" = yes; then lt_prog_compiler_wl='-Wl,' lt_prog_compiler_static='-static' case $host_os in aix*) # All AIX code is PIC. if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support lt_prog_compiler_pic='-fPIC' ;; m68k) # FIXME: we need at least 68020 code to build shared libraries, but # adding the `-m68020' flag to GCC prevents building anything better, # like `-m68040'. lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4' ;; esac ;; beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*) # PIC is the default for these OSes. ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). # Although the cygwin gcc ignores -fPIC, still need this for old-style # (--disable-auto-import) libraries lt_prog_compiler_pic='-DDLL_EXPORT' ;; darwin* | rhapsody*) # PIC is the default on this platform # Common symbols not allowed in MH_DYLIB files lt_prog_compiler_pic='-fno-common' ;; haiku*) # PIC is the default for Haiku. # The "-static" flag exists, but is broken. lt_prog_compiler_static= ;; hpux*) # PIC is the default for 64-bit PA HP-UX, but not for 32-bit # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag # sets the default TLS model and affects inlining. case $host_cpu in hppa*64*) # +Z the default ;; *) lt_prog_compiler_pic='-fPIC' ;; esac ;; interix[3-9]*) # Interix 3.x gcc -fpic/-fPIC options generate broken code. # Instead, we relocate shared libraries at runtime. ;; msdosdjgpp*) # Just because we use GCC doesn't mean we suddenly get shared libraries # on systems that don't support them. lt_prog_compiler_can_build_shared=no enable_shared=no ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; sysv4*MP*) if test -d /usr/nec; then lt_prog_compiler_pic=-Kconform_pic fi ;; *) lt_prog_compiler_pic='-fPIC' ;; esac case $cc_basename in nvcc*) # Cuda Compiler Driver 2.2 lt_prog_compiler_wl='-Xlinker ' if test -n "$lt_prog_compiler_pic"; then lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic" fi ;; esac else # PORTME Check for flag to pass linker flags through the system compiler. case $host_os in aix*) lt_prog_compiler_wl='-Wl,' if test "$host_cpu" = ia64; then # AIX 5 now supports IA64 processor lt_prog_compiler_static='-Bstatic' else lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp' fi ;; mingw* | cygwin* | pw32* | os2* | cegcc*) # This hack is so that the source file can tell whether it is being # built for inclusion in a dll (and should export symbols for example). lt_prog_compiler_pic='-DDLL_EXPORT' ;; hpux9* | hpux10* | hpux11*) lt_prog_compiler_wl='-Wl,' # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but # not for PA HP-UX. case $host_cpu in hppa*64*|ia64*) # +Z the default ;; *) lt_prog_compiler_pic='+Z' ;; esac # Is there a better lt_prog_compiler_static that works with the bundled CC? lt_prog_compiler_static='${wl}-a ${wl}archive' ;; irix5* | irix6* | nonstopux*) lt_prog_compiler_wl='-Wl,' # PIC (with -KPIC) is the default. lt_prog_compiler_static='-non_shared' ;; linux* | k*bsd*-gnu | kopensolaris*-gnu) case $cc_basename in # old Intel for x86_64 which still supported -KPIC. ecc*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-static' ;; # icc used to be incompatible with GCC. # ICC 10 doesn't accept -KPIC any more. icc* | ifort*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; # Lahey Fortran 8.1. lf95*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='--shared' lt_prog_compiler_static='--static' ;; nagfor*) # NAG Fortran compiler lt_prog_compiler_wl='-Wl,-Wl,,' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group compilers (*not* the Pentium gcc compiler, # which looks to be a dead project) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; ccc*) lt_prog_compiler_wl='-Wl,' # All Alpha code is PIC. lt_prog_compiler_static='-non_shared' ;; xl* | bgxl* | bgf* | mpixl*) # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-qpic' lt_prog_compiler_static='-qstaticlink' ;; *) case `$CC -V 2>&1 | sed 5q` in *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*) # Sun Fortran 8.3 passes all unrecognized flags to the linker lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='' ;; *Sun\ F* | *Sun*Fortran*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Qoption ld ' ;; *Sun\ C*) # Sun C 5.9 lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' lt_prog_compiler_wl='-Wl,' ;; *Intel*\ [CF]*Compiler*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fPIC' lt_prog_compiler_static='-static' ;; *Portland\ Group*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-fpic' lt_prog_compiler_static='-Bstatic' ;; esac ;; esac ;; newsos6) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; *nto* | *qnx*) # QNX uses GNU C++, but need to define -shared option too, otherwise # it will coredump. lt_prog_compiler_pic='-fPIC -shared' ;; osf3* | osf4* | osf5*) lt_prog_compiler_wl='-Wl,' # All OSF/1 code is PIC. lt_prog_compiler_static='-non_shared' ;; rdos*) lt_prog_compiler_static='-non_shared' ;; solaris*) lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' case $cc_basename in f77* | f90* | f95* | sunf77* | sunf90* | sunf95*) lt_prog_compiler_wl='-Qoption ld ';; *) lt_prog_compiler_wl='-Wl,';; esac ;; sunos4*) lt_prog_compiler_wl='-Qoption ld ' lt_prog_compiler_pic='-PIC' lt_prog_compiler_static='-Bstatic' ;; sysv4 | sysv4.2uw2* | sysv4.3*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; sysv4*MP*) if test -d /usr/nec ;then lt_prog_compiler_pic='-Kconform_pic' lt_prog_compiler_static='-Bstatic' fi ;; sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_pic='-KPIC' lt_prog_compiler_static='-Bstatic' ;; unicos*) lt_prog_compiler_wl='-Wl,' lt_prog_compiler_can_build_shared=no ;; uts4*) lt_prog_compiler_pic='-pic' lt_prog_compiler_static='-Bstatic' ;; *) lt_prog_compiler_can_build_shared=no ;; esac fi case $host_os in # For platforms which do not support PIC, -DPIC is meaningless: *djgpp*) lt_prog_compiler_pic= ;; *) lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5 $as_echo_n "checking for $compiler option to produce PIC... " >&6; } if ${lt_cv_prog_compiler_pic+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic=$lt_prog_compiler_pic fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5 $as_echo "$lt_cv_prog_compiler_pic" >&6; } lt_prog_compiler_pic=$lt_cv_prog_compiler_pic # # Check to make sure the PIC flag actually works. # if test -n "$lt_prog_compiler_pic"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5 $as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; } if ${lt_cv_prog_compiler_pic_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_pic_works=no ac_outfile=conftest.$ac_objext echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="$lt_prog_compiler_pic -DPIC" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. # The option is referenced via a variable to avoid confusing sed. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>conftest.err) ac_status=$? cat conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s "$ac_outfile"; then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings other than the usual output. $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_pic_works=yes fi fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5 $as_echo "$lt_cv_prog_compiler_pic_works" >&6; } if test x"$lt_cv_prog_compiler_pic_works" = xyes; then case $lt_prog_compiler_pic in "" | " "*) ;; *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;; esac else lt_prog_compiler_pic= lt_prog_compiler_can_build_shared=no fi fi # # Check to make sure the static flag actually works. # wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5 $as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; } if ${lt_cv_prog_compiler_static_works+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_static_works=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS $lt_tmp_static_flag" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler_static_works=yes fi else lt_cv_prog_compiler_static_works=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5 $as_echo "$lt_cv_prog_compiler_static_works" >&6; } if test x"$lt_cv_prog_compiler_static_works" = xyes; then : else lt_prog_compiler_static= fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5 $as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; } if ${lt_cv_prog_compiler_c_o+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler_c_o=no $RM -r conftest 2>/dev/null mkdir conftest cd conftest mkdir out echo "$lt_simple_compile_test_code" > conftest.$ac_ext lt_compiler_flag="-o out/conftest2.$ac_objext" # Insert the option either (1) after the last *FLAGS variable, or # (2) before a word containing "conftest.", or (3) at the end. # Note that $ac_compile itself does not contain backslashes and begins # with a dollar sign (not a hyphen), so the echo should work correctly. lt_compile=`echo "$ac_compile" | $SED \ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \ -e 's:$: $lt_compiler_flag:'` (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5) (eval "$lt_compile" 2>out/conftest.err) ac_status=$? cat out/conftest.err >&5 echo "$as_me:$LINENO: \$? = $ac_status" >&5 if (exit $ac_status) && test -s out/conftest2.$ac_objext then # The compiler can only warn and ignore the option if not recognized # So say no if there are warnings $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2 if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then lt_cv_prog_compiler_c_o=yes fi fi chmod u+w . 2>&5 $RM conftest* # SGI C++ compiler will create directory out/ii_files/ for # template instantiation test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files $RM out/* && rmdir out cd .. $RM -r conftest $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5 $as_echo "$lt_cv_prog_compiler_c_o" >&6; } hard_links="nottested" if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then # do not overwrite the value of need_locks provided by the user { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5 $as_echo_n "checking if we can lock with hard links... " >&6; } hard_links=yes $RM conftest* ln conftest.a conftest.b 2>/dev/null && hard_links=no touch conftest.a ln conftest.a conftest.b 2>&5 || hard_links=no ln conftest.a conftest.b 2>/dev/null && hard_links=no { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5 $as_echo "$hard_links" >&6; } if test "$hard_links" = no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5 $as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;} need_locks=warn fi else need_locks=no fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5 $as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; } runpath_var= allow_undefined_flag= always_export_symbols=no archive_cmds= archive_expsym_cmds= compiler_needs_object=no enable_shared_with_static_runtimes=no export_dynamic_flag_spec= export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols' hardcode_automatic=no hardcode_direct=no hardcode_direct_absolute=no hardcode_libdir_flag_spec= hardcode_libdir_separator= hardcode_minus_L=no hardcode_shlibpath_var=unsupported inherit_rpath=no link_all_deplibs=unknown module_cmds= module_expsym_cmds= old_archive_from_new_cmds= old_archive_from_expsyms_cmds= thread_safe_flag_spec= whole_archive_flag_spec= # include_expsyms should be a list of space-separated symbols to be *always* # included in the symbol list include_expsyms= # exclude_expsyms can be an extended regexp of symbols to exclude # it will be wrapped by ` (' and `)$', so one must not match beginning or # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc', # as well as any symbol that contains `d'. exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*' # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out # platforms (ab)use it in PIC code, but their linkers get confused if # the symbol is explicitly referenced. Since portable code cannot # rely on this symbol name, it's probably fine to never include it in # preloaded symbol tables. # Exclude shared library initialization/finalization symbols. extract_expsyms_cmds= case $host_os in cygwin* | mingw* | pw32* | cegcc*) # FIXME: the MSVC++ port hasn't been tested in a loooong time # When not using gcc, we currently assume that we are using # Microsoft Visual C++. if test "$GCC" != yes; then with_gnu_ld=no fi ;; interix*) # we just hope/assume this is gcc and not c89 (= MSVC++) with_gnu_ld=yes ;; openbsd*) with_gnu_ld=no ;; linux* | k*bsd*-gnu | gnu*) link_all_deplibs=no ;; esac ld_shlibs=yes # On some targets, GNU ld is compatible enough with the native linker # that we're better off using the native interface for both. lt_use_gnu_ld_interface=no if test "$with_gnu_ld" = yes; then case $host_os in aix*) # The AIX port of GNU ld has always aspired to compatibility # with the native linker. However, as the warning in the GNU ld # block says, versions before 2.19.5* couldn't really create working # shared libraries, regardless of the interface used. case `$LD -v 2>&1` in *\ \(GNU\ Binutils\)\ 2.19.5*) ;; *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;; *\ \(GNU\ Binutils\)\ [3-9]*) ;; *) lt_use_gnu_ld_interface=yes ;; esac ;; *) lt_use_gnu_ld_interface=yes ;; esac fi if test "$lt_use_gnu_ld_interface" = yes; then # If archive_cmds runs LD, not CC, wlarc should be empty wlarc='${wl}' # Set some defaults for GNU ld with shared library support. These # are reset later if shared libraries are not supported. Putting them # here allows them to be overridden if necessary. runpath_var=LD_RUN_PATH hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' export_dynamic_flag_spec='${wl}--export-dynamic' # ancient GNU ld didn't support --whole-archive et. al. if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive' else whole_archive_flag_spec= fi supports_anon_versioning=no case `$LD -v 2>&1` in *GNU\ gold*) supports_anon_versioning=yes ;; *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11 *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ... *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ... *\ 2.11.*) ;; # other 2.11 versions *) supports_anon_versioning=yes ;; esac # See if GNU ld supports shared libraries. case $host_os in aix[3-9]*) # On AIX/PPC, the GNU linker is very broken if test "$host_cpu" != ia64; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: the GNU linker, at least up to release 2.19, is reported *** to be unable to reliably create shared libraries on AIX. *** Therefore, libtool is disabling shared libraries support. If you *** really care for shared libraries, you may want to install binutils *** 2.20 or above, or modify your PATH so that a non-GNU linker is found. *** You will then need to restart the configuration process. _LT_EOF fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; beos*) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then allow_undefined_flag=unsupported # Joseph Beckenbach says some releases of gcc # support --undefined. This deserves some investigation. FIXME archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' else ld_shlibs=no fi ;; cygwin* | mingw* | pw32* | cegcc*) # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless, # as there is no search path for DLLs. hardcode_libdir_flag_spec='-L$libdir' export_dynamic_flag_spec='${wl}--export-all-symbols' allow_undefined_flag=unsupported always_export_symbols=no enable_shared_with_static_runtimes=yes export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols' exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname' if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' # If the export-symbols file already is a .def file (1st line # is EXPORTS), use it as is; otherwise, prepend... archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then cp $export_symbols $output_objdir/$soname.def; else echo EXPORTS > $output_objdir/$soname.def; cat $export_symbols >> $output_objdir/$soname.def; fi~ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib' else ld_shlibs=no fi ;; haiku*) archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' link_all_deplibs=yes ;; interix[3-9]*) hardcode_direct=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc. # Instead, shared libraries are loaded at an image base (0x10000000 by # default) and relocated if they conflict, which is a slow very memory # consuming and fragmenting process. To avoid this, we pick a random, # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link # time. Moving up from 0x10000000 also allows more sbrk(2) space. archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib' ;; gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu) tmp_diet=no if test "$host_os" = linux-dietlibc; then case $cc_basename in diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn) esac fi if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \ && test "$tmp_diet" = no then tmp_addflag=' $pic_flag' tmp_sharedflag='-shared' case $cc_basename,$host_cpu in pgcc*) # Portland Group C compiler whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag' ;; pgf77* | pgf90* | pgf95* | pgfortran*) # Portland Group f77 and f90 compilers whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' tmp_addflag=' $pic_flag -Mnomain' ;; ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64 tmp_addflag=' -i_dynamic' ;; efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64 tmp_addflag=' -i_dynamic -nofor_main' ;; ifc* | ifort*) # Intel Fortran compiler tmp_addflag=' -nofor_main' ;; lf95*) # Lahey Fortran 8.1 whole_archive_flag_spec= tmp_sharedflag='--shared' ;; xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below) tmp_sharedflag='-qmkshrobj' tmp_addflag= ;; nvcc*) # Cuda Compiler Driver 2.2 whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes ;; esac case `$CC -V 2>&1 | sed 5q` in *Sun\ C*) # Sun C 5.9 whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive' compiler_needs_object=yes tmp_sharedflag='-G' ;; *Sun\ F*) # Sun Fortran 8.3 tmp_sharedflag='-G' ;; esac archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib' fi case $cc_basename in xlf* | bgf* | bgxlf* | mpixlf*) # IBM XL Fortran 10.1 on PPC cannot create shared libs itself whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib' if test "x$supports_anon_versioning" = xyes; then archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~ echo "local: *; };" >> $output_objdir/$libname.ver~ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib' fi ;; esac else ld_shlibs=no fi ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib' wlarc= else archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' fi ;; solaris*) if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: The releases 2.8.* of the GNU linker cannot reliably *** create shared libraries on Solaris systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.9.1 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*) case `$LD -v 2>&1` in *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*) ld_shlibs=no cat <<_LT_EOF 1>&2 *** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not *** reliably create shared libraries on SCO systems. Therefore, libtool *** is disabling shared libraries support. We urge you to upgrade GNU *** binutils to release 2.16.91.0.3 or newer. Another option is to modify *** your PATH or compiler configuration so that the native linker is *** used, and then restart. _LT_EOF ;; *) # For security reasons, it is highly recommended that you always # use absolute paths for naming shared libraries, and exclude the # DT_RUNPATH tag from executables and libraries. But doing so # requires that you compile everything twice, which is a pain. if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac ;; sunos4*) archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags' wlarc= hardcode_direct=yes hardcode_shlibpath_var=no ;; *) if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib' else ld_shlibs=no fi ;; esac if test "$ld_shlibs" = no; then runpath_var= hardcode_libdir_flag_spec= export_dynamic_flag_spec= whole_archive_flag_spec= fi else # PORTME fill in a description of your system's linker (not GNU ld) case $host_os in aix3*) allow_undefined_flag=unsupported always_export_symbols=yes archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname' # Note: this linker hardcodes the directories in LIBPATH if there # are no directories specified by -L. hardcode_minus_L=yes if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then # Neither direct hardcoding nor static linking is supported with a # broken collect2. hardcode_direct=unsupported fi ;; aix[4-9]*) if test "$host_cpu" = ia64; then # On IA64, the linker does run time linking by default, so we don't # have to do anything special. aix_use_runtimelinking=no exp_sym_flag='-Bexport' no_entry_flag="" else # If we're using GNU nm, then we don't want the "-C" option. # -C means demangle to AIX nm, but means don't demangle with GNU nm # Also, AIX nm treats weak defined symbols like other global # defined symbols, whereas GNU nm marks them as "W". if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' else export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols' fi aix_use_runtimelinking=no # Test if we are trying to use run time linking or normal # AIX style linking. If -brtl is somewhere in LDFLAGS, we # need to do runtime linking. case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*) for ld_flag in $LDFLAGS; do if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then aix_use_runtimelinking=yes break fi done ;; esac exp_sym_flag='-bexport' no_entry_flag='-bnoentry' fi # When large executables or shared objects are built, AIX ld can # have problems creating the table of contents. If linking a library # or program results in "error TOC overflow" add -mminimal-toc to # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS. archive_cmds='' hardcode_direct=yes hardcode_direct_absolute=yes hardcode_libdir_separator=':' link_all_deplibs=yes file_list_spec='${wl}-f,' if test "$GCC" = yes; then case $host_os in aix4.[012]|aix4.[012].*) # We only want to do this on AIX 4.2 and lower, the check # below for broken collect2 doesn't work under 4.3+ collect2name=`${CC} -print-prog-name=collect2` if test -f "$collect2name" && strings "$collect2name" | $GREP resolve_lib_name >/dev/null then # We have reworked collect2 : else # We have old collect2 hardcode_direct=unsupported # It fails to find uninstalled libraries when the uninstalled # path is not listed in the libpath. Setting hardcode_minus_L # to unsupported forces relinking hardcode_minus_L=yes hardcode_libdir_flag_spec='-L$libdir' hardcode_libdir_separator= fi ;; esac shared_flag='-shared' if test "$aix_use_runtimelinking" = yes; then shared_flag="$shared_flag "'${wl}-G' fi link_all_deplibs=no else # not using gcc if test "$host_cpu" = ia64; then # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release # chokes on -Wl,-G. The following line is correct: shared_flag='-G' else if test "$aix_use_runtimelinking" = yes; then shared_flag='${wl}-G' else shared_flag='${wl}-bM:SRE' fi fi fi export_dynamic_flag_spec='${wl}-bexpall' # It seems that -bexpall does not export symbols beginning with # underscore (_), so it is better to generate a list of symbols to export. always_export_symbols=yes if test "$aix_use_runtimelinking" = yes; then # Warning - without using the other runtime loading flags (-brtl), # -berok will link without error, but may produce a broken library. allow_undefined_flag='-berok' # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag" else if test "$host_cpu" = ia64; then hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib' allow_undefined_flag="-z nodefs" archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols" else # Determine the default libpath from the value encoded in an # empty executable. if test "${lt_cv_aix_libpath+set}" = set; then aix_libpath=$lt_cv_aix_libpath else if ${lt_cv_aix_libpath_+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_aix_libpath_sed=' /Import File Strings/,/^$/ { /^0/ { s/^0 *\([^ ]*\) *$/\1/ p } }' lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` # Check for a 64-bit object if we didn't find anything. if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"` fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext if test -z "$lt_cv_aix_libpath_"; then lt_cv_aix_libpath_="/usr/lib:/lib" fi fi aix_libpath=$lt_cv_aix_libpath_ fi hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath" # Warning - without using the other run time loading flags, # -berok will link without error, but may produce a broken library. no_undefined_flag=' ${wl}-bernotok' allow_undefined_flag=' ${wl}-berok' if test "$with_gnu_ld" = yes; then # We only use this code for GNU lds that support --whole-archive. whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive' else # Exported symbols can be pulled into shared objects from archives whole_archive_flag_spec='$convenience' fi archive_cmds_need_lc=yes # This is similar to how AIX traditionally builds its shared libraries. archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname' fi fi ;; amigaos*) case $host_cpu in powerpc) # see comment about AmigaOS4 .so support archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib' archive_expsym_cmds='' ;; m68k) archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)' hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes ;; esac ;; bsdi[45]*) export_dynamic_flag_spec=-rdynamic ;; cygwin* | mingw* | pw32* | cegcc*) # When not using gcc, we currently assume that we are using # Microsoft Visual C++. # hardcode_libdir_flag_spec is actually meaningless, as there is # no search path for DLLs. case $cc_basename in cl*) # Native MSVC hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported always_export_symbols=yes file_list_spec='@' # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames=' archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp; else sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp; fi~ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~ linknames=' # The linker will not automatically build a static lib if we build a DLL. # _LT_TAGVAR(old_archive_from_new_cmds, )='true' enable_shared_with_static_runtimes=yes exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*' export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols' # Don't use ranlib old_postinstall_cmds='chmod 644 $oldlib' postlink_cmds='lt_outputfile="@OUTPUT@"~ lt_tool_outputfile="@TOOL_OUTPUT@"~ case $lt_outputfile in *.exe|*.EXE) ;; *) lt_outputfile="$lt_outputfile.exe" lt_tool_outputfile="$lt_tool_outputfile.exe" ;; esac~ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1; $RM "$lt_outputfile.manifest"; fi' ;; *) # Assume MSVC wrapper hardcode_libdir_flag_spec=' ' allow_undefined_flag=unsupported # Tell ltmain to make .lib files, not .a files. libext=lib # Tell ltmain to make .dll files, not .so files. shrext_cmds=".dll" # FIXME: Setting linknames here is a bad hack. archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames=' # The linker will automatically build a .lib file if we build a DLL. old_archive_from_new_cmds='true' # FIXME: Should let the user specify the lib program. old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs' enable_shared_with_static_runtimes=yes ;; esac ;; darwin* | rhapsody*) archive_cmds_need_lc=no hardcode_direct=no hardcode_automatic=yes hardcode_shlibpath_var=unsupported if test "$lt_cv_ld_force_load" = "yes"; then whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`' else whole_archive_flag_spec='' fi link_all_deplibs=yes allow_undefined_flag="$_lt_dar_allow_undefined" case $cc_basename in ifort*) _lt_dar_can_shared=yes ;; *) _lt_dar_can_shared=$GCC ;; esac if test "$_lt_dar_can_shared" = "yes"; then output_verbose_link_cmd=func_echo_all archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}" module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}" archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}" module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}" else ld_shlibs=no fi ;; dgux*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor # support. Future versions do this automatically, but an explicit c++rt0.o # does not break anything, and helps significantly (at the cost of a little # extra space). freebsd2.2*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; # Unfortunately, older versions of FreeBSD 2 do not have this feature. freebsd2.*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; # FreeBSD 3 and greater uses gcc -shared to do shared libraries. freebsd* | dragonfly*) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; hpux9*) if test "$GCC" = yes; then archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' else archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib' fi hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes export_dynamic_flag_spec='${wl}-E' ;; hpux10*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes fi ;; hpux11*) if test "$GCC" = yes && test "$with_gnu_ld" = no; then case $host_cpu in hppa*64*) archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' ;; esac else case $host_cpu in hppa*64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' ;; ia64*) archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags' ;; *) # Older versions of the 11.00 compiler do not understand -b yet # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does) { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5 $as_echo_n "checking if $CC understands -b... " >&6; } if ${lt_cv_prog_compiler__b+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_prog_compiler__b=no save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -b" echo "$lt_simple_link_test_code" > conftest.$ac_ext if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then # The linker can only warn and ignore the option if not recognized # So say no if there are warnings if test -s conftest.err; then # Append any errors to the config.log. cat conftest.err 1>&5 $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2 if diff conftest.exp conftest.er2 >/dev/null; then lt_cv_prog_compiler__b=yes fi else lt_cv_prog_compiler__b=yes fi fi $RM -r conftest* LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5 $as_echo "$lt_cv_prog_compiler__b" >&6; } if test x"$lt_cv_prog_compiler__b" = xyes; then archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags' fi ;; esac fi if test "$with_gnu_ld" = no; then hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir' hardcode_libdir_separator=: case $host_cpu in hppa*64*|ia64*) hardcode_direct=no hardcode_shlibpath_var=no ;; *) hardcode_direct=yes hardcode_direct_absolute=yes export_dynamic_flag_spec='${wl}-E' # hardcode_minus_L: Not really in the search PATH, # but as the default location of the library. hardcode_minus_L=yes ;; esac fi ;; irix5* | irix6* | nonstopux*) if test "$GCC" = yes; then archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' # Try to use the -exported_symbol ld option, if it does not # work, assume that -exports_file does not work either and # implicitly export all symbols. # This should be the same for all languages, so no per-tag cache variable. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5 $as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; } if ${lt_cv_irix_exported_symbol+:} false; then : $as_echo_n "(cached) " >&6 else save_LDFLAGS="$LDFLAGS" LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int foo (void) { return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : lt_cv_irix_exported_symbol=yes else lt_cv_irix_exported_symbol=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS="$save_LDFLAGS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5 $as_echo "$lt_cv_irix_exported_symbol" >&6; } if test "$lt_cv_irix_exported_symbol" = yes; then archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib' fi else archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: inherit_rpath=yes link_all_deplibs=yes ;; netbsd* | netbsdelf*-gnu) if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out else archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF fi hardcode_libdir_flag_spec='-R$libdir' hardcode_direct=yes hardcode_shlibpath_var=no ;; newsos6) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: hardcode_shlibpath_var=no ;; *nto* | *qnx*) ;; openbsd*) if test -f /usr/libexec/ld.so; then hardcode_direct=yes hardcode_shlibpath_var=no hardcode_direct_absolute=yes if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' export_dynamic_flag_spec='${wl}-E' else case $host_os in openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*) archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-R$libdir' ;; *) archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags' hardcode_libdir_flag_spec='${wl}-rpath,$libdir' ;; esac fi else ld_shlibs=no fi ;; os2*) hardcode_libdir_flag_spec='-L$libdir' hardcode_minus_L=yes allow_undefined_flag=unsupported archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def' old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def' ;; osf3*) if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' fi archive_cmds_need_lc='no' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' hardcode_libdir_separator=: ;; osf4* | osf5*) # as osf3* with the addition of -msym flag if test "$GCC" = yes; then allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*' archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib' hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir' else allow_undefined_flag=' -expect_unresolved \*' archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib' archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp' # Both c and cxx compiler support -rpath directly hardcode_libdir_flag_spec='-rpath $libdir' fi archive_cmds_need_lc='no' hardcode_libdir_separator=: ;; solaris*) no_undefined_flag=' -z defs' if test "$GCC" = yes; then wlarc='${wl}' archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' else case `$CC -V 2>&1` in *"Compilers 5.0"*) wlarc='' archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp' ;; *) wlarc='${wl}' archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp' ;; esac fi hardcode_libdir_flag_spec='-R$libdir' hardcode_shlibpath_var=no case $host_os in solaris2.[0-5] | solaris2.[0-5].*) ;; *) # The compiler driver will combine and reorder linker options, # but understands `-z linker_flag'. GCC discards it without `$wl', # but is careful enough not to reorder. # Supported since Solaris 2.6 (maybe 2.5.1?) if test "$GCC" = yes; then whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract' else whole_archive_flag_spec='-z allextract$convenience -z defaultextract' fi ;; esac link_all_deplibs=yes ;; sunos4*) if test "x$host_vendor" = xsequent; then # Use $CC to link under sequent, because it throws in some extra .o # files that make .init and .fini sections work. archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags' fi hardcode_libdir_flag_spec='-L$libdir' hardcode_direct=yes hardcode_minus_L=yes hardcode_shlibpath_var=no ;; sysv4) case $host_vendor in sni) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=yes # is this really true??? ;; siemens) ## LD is ld it makes a PLAMLIB ## CC just makes a GrossModule. archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags' reload_cmds='$CC -r -o $output$reload_objs' hardcode_direct=no ;; motorola) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_direct=no #Motorola manual says yes, but my tests say they lie ;; esac runpath_var='LD_RUN_PATH' hardcode_shlibpath_var=no ;; sysv4.3*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no export_dynamic_flag_spec='-Bexport' ;; sysv4*MP*) if test -d /usr/nec; then archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_shlibpath_var=no runpath_var=LD_RUN_PATH hardcode_runpath_var=yes ld_shlibs=yes fi ;; sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*) no_undefined_flag='${wl}-z,text' archive_cmds_need_lc=no hardcode_shlibpath_var=no runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; sysv5* | sco3.2v5* | sco5v6*) # Note: We can NOT use -z defs as we might desire, because we do not # link with -lc, and that would cause any symbols used from libc to # always be unresolved, which means just about no library would # ever link correctly. If we're not using GNU ld we use -z text # though, which does catch some bad symbols but isn't as heavy-handed # as -z defs. no_undefined_flag='${wl}-z,text' allow_undefined_flag='${wl}-z,nodefs' archive_cmds_need_lc=no hardcode_shlibpath_var=no hardcode_libdir_flag_spec='${wl}-R,$libdir' hardcode_libdir_separator=':' link_all_deplibs=yes export_dynamic_flag_spec='${wl}-Bexport' runpath_var='LD_RUN_PATH' if test "$GCC" = yes; then archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' else archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags' fi ;; uts4*) archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags' hardcode_libdir_flag_spec='-L$libdir' hardcode_shlibpath_var=no ;; *) ld_shlibs=no ;; esac if test x$host_vendor = xsni; then case $host in sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*) export_dynamic_flag_spec='${wl}-Blargedynsym' ;; esac fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5 $as_echo "$ld_shlibs" >&6; } test "$ld_shlibs" = no && can_build_shared=no with_gnu_ld=$with_gnu_ld # # Do we need to explicitly link libc? # case "x$archive_cmds_need_lc" in x|xyes) # Assume -lc should be added archive_cmds_need_lc=yes if test "$enable_shared" = yes && test "$GCC" = yes; then case $archive_cmds in *'~'*) # FIXME: we may have to deal with multi-command sequences. ;; '$CC '*) # Test whether the compiler implicitly links with -lc since on some # systems, -lgcc has to come before -lc. If gcc already passes -lc # to ld, don't add -lc before -lgcc. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5 $as_echo_n "checking whether -lc should be explicitly linked in... " >&6; } if ${lt_cv_archive_cmds_need_lc+:} false; then : $as_echo_n "(cached) " >&6 else $RM conftest* echo "$lt_simple_compile_test_code" > conftest.$ac_ext if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5 (eval $ac_compile) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } 2>conftest.err; then soname=conftest lib=conftest libobjs=conftest.$ac_objext deplibs= wl=$lt_prog_compiler_wl pic_flag=$lt_prog_compiler_pic compiler_flags=-v linker_flags=-v verstring= output_objdir=. libname=conftest lt_save_allow_undefined_flag=$allow_undefined_flag allow_undefined_flag= if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5 (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } then lt_cv_archive_cmds_need_lc=no else lt_cv_archive_cmds_need_lc=yes fi allow_undefined_flag=$lt_save_allow_undefined_flag else cat conftest.err 1>&5 fi $RM conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5 $as_echo "$lt_cv_archive_cmds_need_lc" >&6; } archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc ;; esac fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5 $as_echo_n "checking dynamic linker characteristics... " >&6; } if test "$GCC" = yes; then case $host_os in darwin*) lt_awk_arg="/^libraries:/,/LR/" ;; *) lt_awk_arg="/^libraries:/" ;; esac case $host_os in mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;; *) lt_sed_strip_eq="s,=/,/,g" ;; esac lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq` case $lt_search_path_spec in *\;*) # if the path contains ";" then we assume it to be the separator # otherwise default to the standard path separator (i.e. ":") - it is # assumed that no part of a normal pathname contains ";" but that should # okay in the real world where ";" in dirpaths is itself problematic. lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'` ;; *) lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"` ;; esac # Ok, now we have the path, separated by spaces, we can step through it # and add multilib dir if necessary. lt_tmp_lt_search_path_spec= lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null` for lt_sys_path in $lt_search_path_spec; do if test -d "$lt_sys_path/$lt_multi_os_dir"; then lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir" else test -d "$lt_sys_path" && \ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path" fi done lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk ' BEGIN {RS=" "; FS="/|\n";} { lt_foo=""; lt_count=0; for (lt_i = NF; lt_i > 0; lt_i--) { if ($lt_i != "" && $lt_i != ".") { if ($lt_i == "..") { lt_count++; } else { if (lt_count == 0) { lt_foo="/" $lt_i lt_foo; } else { lt_count--; } } } } if (lt_foo != "") { lt_freq[lt_foo]++; } if (lt_freq[lt_foo] == 1) { print lt_foo; } }'` # AWK program above erroneously prepends '/' to C:/dos/paths # for these hosts. case $host_os in mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\ $SED 's,/\([A-Za-z]:\),\1,g'` ;; esac sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP` else sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib" fi library_names_spec= libname_spec='lib$name' soname_spec= shrext_cmds=".so" postinstall_cmds= postuninstall_cmds= finish_cmds= finish_eval= shlibpath_var= shlibpath_overrides_runpath=unknown version_type=none dynamic_linker="$host_os ld.so" sys_lib_dlsearch_path_spec="/lib /usr/lib" need_lib_prefix=unknown hardcode_into_libs=no # when you set need_version to no, make sure it does not cause -set_version # flags to be left without arguments need_version=unknown case $host_os in aix3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a' shlibpath_var=LIBPATH # AIX 3 has no versioning support, so we append a major version to the name. soname_spec='${libname}${release}${shared_ext}$major' ;; aix[4-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no hardcode_into_libs=yes if test "$host_cpu" = ia64; then # AIX 5 supports IA64 library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH else # With GCC up to 2.95.x, collect2 would create an import file # for dependence libraries. The import file would start with # the line `#! .'. This would cause the generated library to # depend on `.', always an invalid library. This was fixed in # development snapshots of GCC prior to 3.0. case $host_os in aix4 | aix4.[01] | aix4.[01].*) if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)' echo ' yes ' echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then : else can_build_shared=no fi ;; esac # AIX (on Power*) has no versioning support, so currently we can not hardcode correct # soname into executable. Probably we can add versioning support to # collect2, so additional links can be useful in future. if test "$aix_use_runtimelinking" = yes; then # If using run time linking (on AIX 4.2 or later) use lib.so # instead of lib.a to let people know that these are not # typical AIX shared libraries. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' else # We preserve .a as extension for shared libraries through AIX4.2 # and later when we are not doing run time linking. library_names_spec='${libname}${release}.a $libname.a' soname_spec='${libname}${release}${shared_ext}$major' fi shlibpath_var=LIBPATH fi ;; amigaos*) case $host_cpu in powerpc) # Since July 2007 AmigaOS4 officially supports .so libraries. # When compiling the executable, add -use-dynld -Lsobjs: to the compileline. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' ;; m68k) library_names_spec='$libname.ixlibrary $libname.a' # Create ${libname}_ixlibrary.a entries in /sys/libs. finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done' ;; esac ;; beos*) library_names_spec='${libname}${shared_ext}' dynamic_linker="$host_os ld.so" shlibpath_var=LIBRARY_PATH ;; bsdi[45]*) version_type=linux # correct to gnu/linux during the next big refactor need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib" sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib" # the default ld.so.conf also contains /usr/contrib/lib and # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow # libtool to hard-code these into programs ;; cygwin* | mingw* | pw32* | cegcc*) version_type=windows shrext_cmds=".dll" need_version=no need_lib_prefix=no case $GCC,$cc_basename in yes,*) # gcc library_names_spec='$libname.dll.a' # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname~ chmod a+x \$dldir/$dlname~ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then eval '\''$striplib \$dldir/$dlname'\'' || exit \$?; fi' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes case $host_os in cygwin*) # Cygwin DLLs use 'cyg' prefix rather than 'lib' soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api" ;; mingw* | cegcc*) # MinGW DLLs use traditional 'lib' prefix soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; pw32*) # pw32 DLLs use 'pw' prefix rather than 'lib' library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' ;; esac dynamic_linker='Win32 ld.exe' ;; *,cl*) # Native MSVC libname_spec='$name' soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}' library_names_spec='${libname}.dll.lib' case $build_os in mingw*) sys_lib_search_path_spec= lt_save_ifs=$IFS IFS=';' for lt_path in $LIB do IFS=$lt_save_ifs # Let DOS variable expansion print the short 8.3 style file name. lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"` sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path" done IFS=$lt_save_ifs # Convert to MSYS style. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'` ;; cygwin*) # Convert to unix form, then to dos form, then back to unix form # but this time dos style (no spaces!) so that the unix form looks # like /cygdrive/c/PROGRA~1:/cygdr... sys_lib_search_path_spec=`cygpath --path --unix "$LIB"` sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null` sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` ;; *) sys_lib_search_path_spec="$LIB" if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then # It is most probably a Windows format PATH. sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'` else sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"` fi # FIXME: find the short name or the path components, as spaces are # common. (e.g. "Program Files" -> "PROGRA~1") ;; esac # DLL is installed to $(libdir)/../bin by postinstall_cmds postinstall_cmds='base_file=`basename \${file}`~ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~ dldir=$destdir/`dirname \$dlpath`~ test -d \$dldir || mkdir -p \$dldir~ $install_prog $dir/$dlname \$dldir/$dlname' postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~ dlpath=$dir/\$dldll~ $RM \$dlpath' shlibpath_overrides_runpath=yes dynamic_linker='Win32 link.exe' ;; *) # Assume MSVC wrapper library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib' dynamic_linker='Win32 ld.exe' ;; esac # FIXME: first we should search . and the directory the executable is in shlibpath_var=PATH ;; darwin* | rhapsody*) dynamic_linker="$host_os dyld" version_type=darwin need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext' soname_spec='${libname}${release}${major}$shared_ext' shlibpath_overrides_runpath=yes shlibpath_var=DYLD_LIBRARY_PATH shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`' sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib" sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib' ;; dgux*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; freebsd* | dragonfly*) # DragonFly does not have aout. When/if they implement a new # versioning mechanism, adjust this. if test -x /usr/bin/objformat; then objformat=`/usr/bin/objformat` else case $host_os in freebsd[23].*) objformat=aout ;; *) objformat=elf ;; esac fi version_type=freebsd-$objformat case $version_type in freebsd-elf*) library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' need_version=no need_lib_prefix=no ;; freebsd-*) library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix' need_version=yes ;; esac shlibpath_var=LD_LIBRARY_PATH case $host_os in freebsd2.*) shlibpath_overrides_runpath=yes ;; freebsd3.[01]* | freebsdelf3.[01]*) shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; freebsd3.[2-9]* | freebsdelf3.[2-9]* | \ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1) shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; *) # from 4.6 on, and DragonFly shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; esac ;; gnu*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; haiku*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no dynamic_linker="$host_os runtime_loader" library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LIBRARY_PATH shlibpath_overrides_runpath=yes sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib' hardcode_into_libs=yes ;; hpux9* | hpux10* | hpux11*) # Give a soname corresponding to the major version so that dld.sl refuses to # link against other versions. version_type=sunos need_lib_prefix=no need_version=no case $host_cpu in ia64*) shrext_cmds='.so' hardcode_into_libs=yes dynamic_linker="$host_os dld.so" shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' if test "X$HPUX_IA64_MODE" = X32; then sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib" else sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64" fi sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; hppa*64*) shrext_cmds='.sl' hardcode_into_libs=yes dynamic_linker="$host_os dld.sl" shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH shlibpath_overrides_runpath=yes # Unless +noenvvar is specified. library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64" sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec ;; *) shrext_cmds='.sl' dynamic_linker="$host_os dld.sl" shlibpath_var=SHLIB_PATH shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' ;; esac # HP-UX runs *really* slowly unless shared libraries are mode 555, ... postinstall_cmds='chmod 555 $lib' # or fails outright, so override atomically: install_override_mode=555 ;; interix[3-9]*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; irix5* | irix6* | nonstopux*) case $host_os in nonstopux*) version_type=nonstopux ;; *) if test "$lt_cv_prog_gnu_ld" = yes; then version_type=linux # correct to gnu/linux during the next big refactor else version_type=irix fi ;; esac need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}' case $host_os in irix5* | nonstopux*) libsuff= shlibsuff= ;; *) case $LD in # libtool.m4 will add one of these switches to LD *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ") libsuff= shlibsuff= libmagic=32-bit;; *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ") libsuff=32 shlibsuff=N32 libmagic=N32;; *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ") libsuff=64 shlibsuff=64 libmagic=64-bit;; *) libsuff= shlibsuff= libmagic=never-match;; esac ;; esac shlibpath_var=LD_LIBRARY${shlibsuff}_PATH shlibpath_overrides_runpath=no sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}" sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}" hardcode_into_libs=yes ;; # No shared lib support for Linux oldld, aout, or coff. linux*oldld* | linux*aout* | linux*coff*) dynamic_linker=no ;; # This must be glibc/ELF. linux* | k*bsd*-gnu | kopensolaris*-gnu) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no # Some binutils ld are patched to set DT_RUNPATH if ${lt_cv_shlibpath_overrides_runpath+:} false; then : $as_echo_n "(cached) " >&6 else lt_cv_shlibpath_overrides_runpath=no save_LDFLAGS=$LDFLAGS save_libdir=$libdir eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\"" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then : lt_cv_shlibpath_overrides_runpath=yes fi fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LDFLAGS=$save_LDFLAGS libdir=$save_libdir fi shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath # This implies no fast_install, which is unacceptable. # Some rework will be needed to allow for fast_install # before this can be enabled. hardcode_into_libs=yes # Append ld.so.conf contents to the search path if test -f /etc/ld.so.conf; then lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '` sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra" fi # We used to test for /lib/ld.so.1 and disable shared libraries on # powerpc, because MkLinux only supported shared libraries with the # GNU dynamic linker. Since this was broken with cross compilers, # most powerpc-linux boxes support dynamic linking these days and # people can always --disable-shared, the test was removed, and we # assume the GNU/Linux dynamic linker is in use. dynamic_linker='GNU/Linux ld.so' ;; netbsdelf*-gnu) version_type=linux need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='NetBSD ld.elf_so' ;; netbsd*) version_type=sunos need_lib_prefix=no need_version=no if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' dynamic_linker='NetBSD (a.out) ld.so' else library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' dynamic_linker='NetBSD ld.elf_so' fi shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes ;; newsos6) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes ;; *nto* | *qnx*) version_type=qnx need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes dynamic_linker='ldqnx.so' ;; openbsd*) version_type=sunos sys_lib_dlsearch_path_spec="/usr/lib" need_lib_prefix=no # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs. case $host_os in openbsd3.3 | openbsd3.3.*) need_version=yes ;; *) need_version=no ;; esac library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir' shlibpath_var=LD_LIBRARY_PATH if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then case $host_os in openbsd2.[89] | openbsd2.[89].*) shlibpath_overrides_runpath=no ;; *) shlibpath_overrides_runpath=yes ;; esac else shlibpath_overrides_runpath=yes fi ;; os2*) libname_spec='$name' shrext_cmds=".dll" need_lib_prefix=no library_names_spec='$libname${shared_ext} $libname.a' dynamic_linker='OS/2 ld.exe' shlibpath_var=LIBPATH ;; osf3* | osf4* | osf5*) version_type=osf need_lib_prefix=no need_version=no soname_spec='${libname}${release}${shared_ext}$major' library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib" sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec" ;; rdos*) dynamic_linker=no ;; solaris*) version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes # ldd complains unless libraries are executable postinstall_cmds='chmod +x $lib' ;; sunos4*) version_type=sunos library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix' finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes if test "$with_gnu_ld" = yes; then need_lib_prefix=no fi need_version=yes ;; sysv4 | sysv4.3*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH case $host_vendor in sni) shlibpath_overrides_runpath=no need_lib_prefix=no runpath_var=LD_RUN_PATH ;; siemens) need_lib_prefix=no ;; motorola) need_lib_prefix=no need_version=no shlibpath_overrides_runpath=no sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib' ;; esac ;; sysv4*MP*) if test -d /usr/nec ;then version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}' soname_spec='$libname${shared_ext}.$major' shlibpath_var=LD_LIBRARY_PATH fi ;; sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*) version_type=freebsd-elf need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=yes hardcode_into_libs=yes if test "$with_gnu_ld" = yes; then sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib' else sys_lib_search_path_spec='/usr/ccs/lib /usr/lib' case $host_os in sco3.2v5*) sys_lib_search_path_spec="$sys_lib_search_path_spec /lib" ;; esac fi sys_lib_dlsearch_path_spec='/usr/lib' ;; tpf*) # TPF is a cross-target only. Preferred cross-host = GNU/Linux. version_type=linux # correct to gnu/linux during the next big refactor need_lib_prefix=no need_version=no library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' shlibpath_var=LD_LIBRARY_PATH shlibpath_overrides_runpath=no hardcode_into_libs=yes ;; uts4*) version_type=linux # correct to gnu/linux during the next big refactor library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}' soname_spec='${libname}${release}${shared_ext}$major' shlibpath_var=LD_LIBRARY_PATH ;; *) dynamic_linker=no ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5 $as_echo "$dynamic_linker" >&6; } test "$dynamic_linker" = no && can_build_shared=no variables_saved_for_relink="PATH $shlibpath_var $runpath_var" if test "$GCC" = yes; then variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH" fi if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec" fi if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5 $as_echo_n "checking how to hardcode library paths into programs... " >&6; } hardcode_action= if test -n "$hardcode_libdir_flag_spec" || test -n "$runpath_var" || test "X$hardcode_automatic" = "Xyes" ; then # We can hardcode non-existent directories. if test "$hardcode_direct" != no && # If the only mechanism to avoid hardcoding is shlibpath_var, we # have to relink, otherwise we might link with an installed library # when we should be linking with a yet-to-be-installed one ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no && test "$hardcode_minus_L" != no; then # Linking always hardcodes the temporary library directory. hardcode_action=relink else # We can link without hardcoding, and we can hardcode nonexisting dirs. hardcode_action=immediate fi else # We cannot hardcode anything, or else we can only hardcode existing # directories. hardcode_action=unsupported fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5 $as_echo "$hardcode_action" >&6; } if test "$hardcode_action" = relink || test "$inherit_rpath" = yes; then # Fast installation is not supported enable_fast_install=no elif test "$shlibpath_overrides_runpath" = yes || test "$enable_shared" = no; then # Fast installation is not necessary enable_fast_install=needless fi if test "x$enable_dlopen" != xyes; then enable_dlopen=unknown enable_dlopen_self=unknown enable_dlopen_self_static=unknown else lt_cv_dlopen=no lt_cv_dlopen_libs= case $host_os in beos*) lt_cv_dlopen="load_add_on" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes ;; mingw* | pw32* | cegcc*) lt_cv_dlopen="LoadLibrary" lt_cv_dlopen_libs= ;; cygwin*) lt_cv_dlopen="dlopen" lt_cv_dlopen_libs= ;; darwin*) # if libdl is installed we need to link against it { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else lt_cv_dlopen="dyld" lt_cv_dlopen_libs= lt_cv_dlopen_self=yes fi ;; *) ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load" if test "x$ac_cv_func_shl_load" = xyes; then : lt_cv_dlopen="shl_load" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5 $as_echo_n "checking for shl_load in -ldld... " >&6; } if ${ac_cv_lib_dld_shl_load+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char shl_load (); int main () { return shl_load (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_shl_load=yes else ac_cv_lib_dld_shl_load=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5 $as_echo "$ac_cv_lib_dld_shl_load" >&6; } if test "x$ac_cv_lib_dld_shl_load" = xyes; then : lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld" else ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen" if test "x$ac_cv_func_dlopen" = xyes; then : lt_cv_dlopen="dlopen" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5 $as_echo_n "checking for dlopen in -lsvld... " >&6; } if ${ac_cv_lib_svld_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsvld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_svld_dlopen=yes else ac_cv_lib_svld_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5 $as_echo "$ac_cv_lib_svld_dlopen" >&6; } if test "x$ac_cv_lib_svld_dlopen" = xyes; then : lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld" else { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5 $as_echo_n "checking for dld_link in -ldld... " >&6; } if ${ac_cv_lib_dld_dld_link+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldld $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dld_link (); int main () { return dld_link (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dld_dld_link=yes else ac_cv_lib_dld_dld_link=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5 $as_echo "$ac_cv_lib_dld_dld_link" >&6; } if test "x$ac_cv_lib_dld_dld_link" = xyes; then : lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld" fi fi fi fi fi fi ;; esac if test "x$lt_cv_dlopen" != xno; then enable_dlopen=yes else enable_dlopen=no fi case $lt_cv_dlopen in dlopen) save_CPPFLAGS="$CPPFLAGS" test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H" save_LDFLAGS="$LDFLAGS" wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\" save_LIBS="$LIBS" LIBS="$lt_cv_dlopen_libs $LIBS" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5 $as_echo_n "checking whether a program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;; esac else : # compilation failed lt_cv_dlopen_self=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5 $as_echo "$lt_cv_dlopen_self" >&6; } if test "x$lt_cv_dlopen_self" = xyes; then wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\" { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5 $as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; } if ${lt_cv_dlopen_self_static+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : lt_cv_dlopen_self_static=cross else lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 lt_status=$lt_dlunknown cat > conftest.$ac_ext <<_LT_EOF #line $LINENO "configure" #include "confdefs.h" #if HAVE_DLFCN_H #include #endif #include #ifdef RTLD_GLOBAL # define LT_DLGLOBAL RTLD_GLOBAL #else # ifdef DL_GLOBAL # define LT_DLGLOBAL DL_GLOBAL # else # define LT_DLGLOBAL 0 # endif #endif /* We may have to define LT_DLLAZY_OR_NOW in the command line if we find out it does not work in some platform. */ #ifndef LT_DLLAZY_OR_NOW # ifdef RTLD_LAZY # define LT_DLLAZY_OR_NOW RTLD_LAZY # else # ifdef DL_LAZY # define LT_DLLAZY_OR_NOW DL_LAZY # else # ifdef RTLD_NOW # define LT_DLLAZY_OR_NOW RTLD_NOW # else # ifdef DL_NOW # define LT_DLLAZY_OR_NOW DL_NOW # else # define LT_DLLAZY_OR_NOW 0 # endif # endif # endif # endif #endif /* When -fvisbility=hidden is used, assume the code has been annotated correspondingly for the symbols needed. */ #if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3)) int fnord () __attribute__((visibility("default"))); #endif int fnord () { return 42; } int main () { void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW); int status = $lt_dlunknown; if (self) { if (dlsym (self,"fnord")) status = $lt_dlno_uscore; else { if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore; else puts (dlerror ()); } /* dlclose (self); */ } else puts (dlerror ()); return status; } _LT_EOF if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5 (eval $ac_link) 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then (./conftest; exit; ) >&5 2>/dev/null lt_status=$? case x$lt_status in x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;; x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;; esac else : # compilation failed lt_cv_dlopen_self_static=no fi fi rm -fr conftest* fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5 $as_echo "$lt_cv_dlopen_self_static" >&6; } fi CPPFLAGS="$save_CPPFLAGS" LDFLAGS="$save_LDFLAGS" LIBS="$save_LIBS" ;; esac case $lt_cv_dlopen_self in yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;; *) enable_dlopen_self=unknown ;; esac case $lt_cv_dlopen_self_static in yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;; *) enable_dlopen_self_static=unknown ;; esac fi striplib= old_striplib= { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5 $as_echo_n "checking whether stripping libraries is possible... " >&6; } if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then test -z "$old_striplib" && old_striplib="$STRIP --strip-debug" test -z "$striplib" && striplib="$STRIP --strip-unneeded" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else # FIXME - insert some real tests, host_os isn't really good enough case $host_os in darwin*) if test -n "$STRIP" ; then striplib="$STRIP -x" old_striplib="$STRIP -S" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi ;; *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } ;; esac fi # Report which library types will actually be built { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5 $as_echo_n "checking if libtool supports shared libraries... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5 $as_echo "$can_build_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5 $as_echo_n "checking whether to build shared libraries... " >&6; } test "$can_build_shared" = "no" && enable_shared=no # On AIX, shared libraries and static libraries use the same namespace, and # are all built from PIC. case $host_os in aix3*) test "$enable_shared" = yes && enable_static=no if test -n "$RANLIB"; then archive_cmds="$archive_cmds~\$RANLIB \$lib" postinstall_cmds='$RANLIB $lib' fi ;; aix[4-9]*) if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then test "$enable_shared" = yes && enable_static=no fi ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5 $as_echo "$enable_shared" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5 $as_echo_n "checking whether to build static libraries... " >&6; } # Make sure either enable_shared or enable_static is yes. test "$enable_shared" = yes || enable_static=yes { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5 $as_echo "$enable_static" >&6; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu CC="$lt_save_CC" ac_config_commands="$ac_config_commands libtool" # Only expand once: ac_fn_c_check_func "$LINENO" "ppoll" "ac_cv_func_ppoll" if test "x$ac_cv_func_ppoll" = xyes; then : dummy=yes else $as_echo "#define NEED_PPOLL 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5 $as_echo_n "checking for dlopen in -ldl... " >&6; } if ${ac_cv_lib_dl_dlopen+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char dlopen (); int main () { return dlopen (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_dl_dlopen=yes else ac_cv_lib_dl_dlopen=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5 $as_echo "$ac_cv_lib_dl_dlopen" >&6; } if test "x$ac_cv_lib_dl_dlopen" = xyes; then : dummy=yes else as_fn_error $? "dynamic linking loader is required" "$LINENO" 5 fi ac_fn_c_check_header_mongrel "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default" if test "x$ac_cv_header_sys_inotify_h" = xyes; then : $as_echo "#define HAVE_SYS_INOTIFY_H 1" >>confdefs.h else as_fn_error $? "inotify headers are required and missing" "$LINENO" 5 fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for DBUS" >&5 $as_echo_n "checking for DBUS... " >&6; } if test -n "$DBUS_CFLAGS"; then pkg_cv_DBUS_CFLAGS="$DBUS_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.4\""; } >&5 ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.4") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DBUS_CFLAGS=`$PKG_CONFIG --cflags "dbus-1 >= 1.4" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$DBUS_LIBS"; then pkg_cv_DBUS_LIBS="$DBUS_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.4\""; } >&5 ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.4") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_DBUS_LIBS=`$PKG_CONFIG --libs "dbus-1 >= 1.4" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then DBUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "dbus-1 >= 1.4" 2>&1` else DBUS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "dbus-1 >= 1.4" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$DBUS_PKG_ERRORS" >&5 as_fn_error $? "D-Bus >= 1.4 is required" "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "D-Bus >= 1.4 is required" "$LINENO" 5 else DBUS_CFLAGS=$pkg_cv_DBUS_CFLAGS DBUS_LIBS=$pkg_cv_DBUS_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } dummy=yes fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB" >&5 $as_echo_n "checking for GLIB... " >&6; } if test -n "$GLIB_CFLAGS"; then pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.28\""; } >&5 ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.28") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.28" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$GLIB_LIBS"; then pkg_cv_GLIB_LIBS="$GLIB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.28\""; } >&5 ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.28") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GLIB_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.28" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.28" 2>&1` else GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.28" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$GLIB_PKG_ERRORS" >&5 as_fn_error $? "GLib >= 2.28 is required" "$LINENO" 5 elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } as_fn_error $? "GLib >= 2.28 is required" "$LINENO" 5 else GLIB_CFLAGS=$pkg_cv_GLIB_CFLAGS GLIB_LIBS=$pkg_cv_GLIB_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } dummy=yes fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ALSA" >&5 $as_echo_n "checking for ALSA... " >&6; } if test -n "$ALSA_CFLAGS"; then pkg_cv_ALSA_CFLAGS="$ALSA_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5 ($PKG_CONFIG --exists --print-errors "alsa") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ALSA_CFLAGS=`$PKG_CONFIG --cflags "alsa" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$ALSA_LIBS"; then pkg_cv_ALSA_LIBS="$ALSA_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5 ($PKG_CONFIG --exists --print-errors "alsa") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_ALSA_LIBS=`$PKG_CONFIG --libs "alsa" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then ALSA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "alsa" 2>&1` else ALSA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "alsa" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$ALSA_PKG_ERRORS" >&5 alsa_found=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } alsa_found=no else ALSA_CFLAGS=$pkg_cv_ALSA_CFLAGS ALSA_LIBS=$pkg_cv_ALSA_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } alsa_found=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5 $as_echo_n "checking for clock_gettime in -lrt... " >&6; } if ${ac_cv_lib_rt_clock_gettime+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char clock_gettime (); int main () { return clock_gettime (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_rt_clock_gettime=yes else ac_cv_lib_rt_clock_gettime=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5 $as_echo "$ac_cv_lib_rt_clock_gettime" >&6; } if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then : ALSA_LIBS="$ALSA_LIBS -lrt" else alsa_found=no fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GSTREAMER" >&5 $as_echo_n "checking for GSTREAMER... " >&6; } if test -n "$GSTREAMER_CFLAGS"; then pkg_cv_GSTREAMER_CFLAGS="$GSTREAMER_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10\""; } >&5 ($PKG_CONFIG --exists --print-errors "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GSTREAMER_CFLAGS=`$PKG_CONFIG --cflags "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$GSTREAMER_LIBS"; then pkg_cv_GSTREAMER_LIBS="$GSTREAMER_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10\""; } >&5 ($PKG_CONFIG --exists --print-errors "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_GSTREAMER_LIBS=`$PKG_CONFIG --libs "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then GSTREAMER_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10" 2>&1` else GSTREAMER_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$GSTREAMER_PKG_ERRORS" >&5 { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GStreamer library version 0.10.30 or later is required" >&5 $as_echo "$as_me: WARNING: GStreamer library version 0.10.30 or later is required" >&2;};gstreamer_found=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GStreamer library version 0.10.30 or later is required" >&5 $as_echo "$as_me: WARNING: GStreamer library version 0.10.30 or later is required" >&2;};gstreamer_found=no else GSTREAMER_CFLAGS=$pkg_cv_GSTREAMER_CFLAGS GSTREAMER_LIBS=$pkg_cv_GSTREAMER_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } gstreamer_found=yes fi GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10` pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for USB" >&5 $as_echo_n "checking for USB... " >&6; } if test -n "$USB_CFLAGS"; then pkg_cv_USB_CFLAGS="$USB_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb\""; } >&5 ($PKG_CONFIG --exists --print-errors "libusb") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_USB_CFLAGS=`$PKG_CONFIG --cflags "libusb" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$USB_LIBS"; then pkg_cv_USB_LIBS="$USB_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb\""; } >&5 ($PKG_CONFIG --exists --print-errors "libusb") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_USB_LIBS=`$PKG_CONFIG --libs "libusb" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then USB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libusb" 2>&1` else USB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libusb" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$USB_PKG_ERRORS" >&5 usb_found=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } usb_found=no else USB_CFLAGS=$pkg_cv_USB_CFLAGS USB_LIBS=$pkg_cv_USB_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } usb_found=yes fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usb_get_busses in -lusb" >&5 $as_echo_n "checking for usb_get_busses in -lusb... " >&6; } if ${ac_cv_lib_usb_usb_get_busses+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lusb $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char usb_get_busses (); int main () { return usb_get_busses (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_usb_usb_get_busses=yes else ac_cv_lib_usb_usb_get_busses=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_usb_usb_get_busses" >&5 $as_echo "$ac_cv_lib_usb_usb_get_busses" >&6; } if test "x$ac_cv_lib_usb_usb_get_busses" = xyes; then : dummy=yes else $as_echo "#define NEED_USB_GET_BUSSES 1" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usb_interrupt_read in -lusb" >&5 $as_echo_n "checking for usb_interrupt_read in -lusb... " >&6; } if ${ac_cv_lib_usb_usb_interrupt_read+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lusb $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char usb_interrupt_read (); int main () { return usb_interrupt_read (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_usb_usb_interrupt_read=yes else ac_cv_lib_usb_usb_interrupt_read=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_usb_usb_interrupt_read" >&5 $as_echo "$ac_cv_lib_usb_usb_interrupt_read" >&6; } if test "x$ac_cv_lib_usb_usb_interrupt_read" = xyes; then : dummy=yes else $as_echo "#define NEED_USB_INTERRUPT_READ 1" >>confdefs.h fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for UDEV" >&5 $as_echo_n "checking for UDEV... " >&6; } if test -n "$UDEV_CFLAGS"; then pkg_cv_UDEV_CFLAGS="$UDEV_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev\""; } >&5 ($PKG_CONFIG --exists --print-errors "libudev") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_UDEV_CFLAGS=`$PKG_CONFIG --cflags "libudev" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$UDEV_LIBS"; then pkg_cv_UDEV_LIBS="$UDEV_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev\""; } >&5 ($PKG_CONFIG --exists --print-errors "libudev") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_UDEV_LIBS=`$PKG_CONFIG --libs "libudev" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then UDEV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libudev" 2>&1` else UDEV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libudev" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$UDEV_PKG_ERRORS" >&5 udev_found=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } udev_found=no else UDEV_CFLAGS=$pkg_cv_UDEV_CFLAGS UDEV_LIBS=$pkg_cv_UDEV_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } udev_found=yes fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for SNDFILE" >&5 $as_echo_n "checking for SNDFILE... " >&6; } if test -n "$SNDFILE_CFLAGS"; then pkg_cv_SNDFILE_CFLAGS="$SNDFILE_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sndfile\""; } >&5 ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SNDFILE_CFLAGS=`$PKG_CONFIG --cflags "sndfile" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$SNDFILE_LIBS"; then pkg_cv_SNDFILE_LIBS="$SNDFILE_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sndfile\""; } >&5 ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_SNDFILE_LIBS=`$PKG_CONFIG --libs "sndfile" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then SNDFILE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sndfile" 2>&1` else SNDFILE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sndfile" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$SNDFILE_PKG_ERRORS" >&5 sndfile_found=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } sndfile_found=no else SNDFILE_CFLAGS=$pkg_cv_SNDFILE_CFLAGS SNDFILE_LIBS=$pkg_cv_SNDFILE_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } sndfile_found=yes fi # Check whether --with-ouifile was given. if test "${with_ouifile+set}" = set; then : withval=$with_ouifile; ac_with_ouifile=$withval else ac_with_ouifile="/var/lib/misc/oui.txt" fi cat >>confdefs.h <<_ACEOF #define OUIFILE "$ac_with_ouifile" _ACEOF ac_fn_c_check_header_mongrel "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default" if test "x$ac_cv_header_readline_readline_h" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lreadline" >&5 $as_echo_n "checking for main in -lreadline... " >&6; } if ${ac_cv_lib_readline_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lreadline $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_readline_main=yes else ac_cv_lib_readline_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_main" >&5 $as_echo "$ac_cv_lib_readline_main" >&6; } if test "x$ac_cv_lib_readline_main" = xyes; then : readline_found=yes READLINE_LIBS="-lreadline" else readline_found=no fi fi pkg_failed=no { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CHECK" >&5 $as_echo_n "checking for CHECK... " >&6; } if test -n "$CHECK_CFLAGS"; then pkg_cv_CHECK_CFLAGS="$CHECK_CFLAGS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.6\""; } >&5 ($PKG_CONFIG --exists --print-errors "check >= 0.9.6") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CHECK_CFLAGS=`$PKG_CONFIG --cflags "check >= 0.9.6" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test -n "$CHECK_LIBS"; then pkg_cv_CHECK_LIBS="$CHECK_LIBS" elif test -n "$PKG_CONFIG"; then if test -n "$PKG_CONFIG" && \ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.6\""; } >&5 ($PKG_CONFIG --exists --print-errors "check >= 0.9.6") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then pkg_cv_CHECK_LIBS=`$PKG_CONFIG --libs "check >= 0.9.6" 2>/dev/null` test "x$?" != "x0" && pkg_failed=yes else pkg_failed=yes fi else pkg_failed=untried fi if test $pkg_failed = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then _pkg_short_errors_supported=yes else _pkg_short_errors_supported=no fi if test $_pkg_short_errors_supported = yes; then CHECK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "check >= 0.9.6" 2>&1` else CHECK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "check >= 0.9.6" 2>&1` fi # Put the nasty error message in config.log where it belongs echo "$CHECK_PKG_ERRORS" >&5 check_found=no elif test $pkg_failed = untried; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } check_found=no else CHECK_CFLAGS=$pkg_cv_CHECK_CFLAGS CHECK_LIBS=$pkg_cv_CHECK_LIBS { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } check_found=yes fi debug_enable=no optimization_enable=yes fortify_enable=yes pie_enable=yes sndfile_enable=${sndfile_found} hal_enable=no usb_enable=${usb_found} alsa_enable=${alsa_found} gstreamer_enable=${gstreamer_found} audio_enable=yes input_enable=yes serial_enable=yes network_enable=yes sap_enable=no service_enable=yes health_enable=no pnat_enable=no tools_enable=yes hidd_enable=no pand_enable=no dund_enable=no cups_enable=no test_enable=no bccmd_enable=no pcmcia_enable=no hid2hci_enable=no dfutool_enable=no datafiles_enable=yes telephony_driver=dummy maemo6_enable=no sap_driver=dummy dbusoob_enable=no wiimote_enable=no gatt_enable=no # Check whether --enable-optimization was given. if test "${enable_optimization+set}" = set; then : enableval=$enable_optimization; optimization_enable=${enableval} fi # Check whether --enable-fortify was given. if test "${enable_fortify+set}" = set; then : enableval=$enable_fortify; fortify_enable=${enableval} fi # Check whether --enable-pie was given. if test "${enable_pie+set}" = set; then : enableval=$enable_pie; pie_enable=${enableval} fi # Check whether --enable-network was given. if test "${enable_network+set}" = set; then : enableval=$enable_network; network_enable=${enableval} fi # Check whether --enable-sap was given. if test "${enable_sap+set}" = set; then : enableval=$enable_sap; sap_enable=${enableval} fi # Check whether --with-sap was given. if test "${with_sap+set}" = set; then : withval=$with_sap; sap_driver=${withval} fi SAP_DRIVER=sap-${sap_driver}.c # Check whether --enable-serial was given. if test "${enable_serial+set}" = set; then : enableval=$enable_serial; serial_enable=${enableval} fi # Check whether --enable-input was given. if test "${enable_input+set}" = set; then : enableval=$enable_input; input_enable=${enableval} fi # Check whether --enable-audio was given. if test "${enable_audio+set}" = set; then : enableval=$enable_audio; audio_enable=${enableval} fi # Check whether --enable-service was given. if test "${enable_service+set}" = set; then : enableval=$enable_service; service_enable=${enableval} fi # Check whether --enable-health was given. if test "${enable_health+set}" = set; then : enableval=$enable_health; health_enable=${enableval} fi # Check whether --enable-pnat was given. if test "${enable_pnat+set}" = set; then : enableval=$enable_pnat; pnat_enable=${enableval} fi # Check whether --enable-gstreamer was given. if test "${enable_gstreamer+set}" = set; then : enableval=$enable_gstreamer; gstreamer_enable=${enableval} fi # Check whether --enable-alsa was given. if test "${enable_alsa+set}" = set; then : enableval=$enable_alsa; alsa_enable=${enableval} fi # Check whether --enable-usb was given. if test "${enable_usb+set}" = set; then : enableval=$enable_usb; usb_enable=${enableval} fi # Check whether --enable-tools was given. if test "${enable_tools+set}" = set; then : enableval=$enable_tools; tools_enable=${enableval} fi # Check whether --enable-bccmd was given. if test "${enable_bccmd+set}" = set; then : enableval=$enable_bccmd; bccmd_enable=${enableval} fi # Check whether --enable-pcmcia was given. if test "${enable_pcmcia+set}" = set; then : enableval=$enable_pcmcia; pcmcia_enable=${enableval} fi # Check whether --enable-hid2hci was given. if test "${enable_hid2hci+set}" = set; then : enableval=$enable_hid2hci; hid2hci_enable=${enableval} fi # Check whether --enable-dfutool was given. if test "${enable_dfutool+set}" = set; then : enableval=$enable_dfutool; dfutool_enable=${enableval} fi # Check whether --enable-hidd was given. if test "${enable_hidd+set}" = set; then : enableval=$enable_hidd; hidd_enable=${enableval} fi # Check whether --enable-pand was given. if test "${enable_pand+set}" = set; then : enableval=$enable_pand; pand_enable=${enableval} fi # Check whether --enable-dund was given. if test "${enable_dund+set}" = set; then : enableval=$enable_dund; dund_enable=${enableval} fi # Check whether --enable-cups was given. if test "${enable_cups+set}" = set; then : enableval=$enable_cups; cups_enable=${enableval} fi # Check whether --enable-test was given. if test "${enable_test+set}" = set; then : enableval=$enable_test; test_enable=${enableval} fi # Check whether --enable-datafiles was given. if test "${enable_datafiles+set}" = set; then : enableval=$enable_datafiles; datafiles_enable=${enableval} fi # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; debug_enable=${enableval} fi # Check whether --with-telephony was given. if test "${with_telephony+set}" = set; then : withval=$with_telephony; telephony_driver=${withval} fi TELEPHONY_DRIVER=telephony-${telephony_driver}.c # Check whether --enable-maemo6 was given. if test "${enable_maemo6+set}" = set; then : enableval=$enable_maemo6; maemo6_enable=${enableval} fi # Check whether --enable-dbusoob was given. if test "${enable_dbusoob+set}" = set; then : enableval=$enable_dbusoob; dbusoob_enable=${enableval} fi # Check whether --enable-wiimote was given. if test "${enable_wiimote+set}" = set; then : enableval=$enable_wiimote; wiimote_enable=${enableval} fi # Check whether --enable-hal was given. if test "${enable_hal+set}" = set; then : enableval=$enable_hal; hal_enable=${enableval} fi # Check whether --enable-gatt was given. if test "${enable_gatt+set}" = set; then : enableval=$enable_gatt; gatt_enable=${enableval} fi misc_cflags="" misc_ldflags="" if (test "${fortify_enable}" = "yes"); then misc_cflags="$misc_cflags -D_FORTIFY_SOURCE=2" fi if (test "${pie_enable}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then misc_cflags="$misc_cflags -fPIC" misc_ldflags="$misc_ldflags -pie" fi if (test "${debug_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then misc_cflags="$misc_cflags -g" fi if (test "${optimization_enable}" = "no"); then misc_cflags="$misc_cflags -O0" fi MISC_CFLAGS=$misc_cflags MISC_LDFLAGS=$misc_ldflags if (test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"); then $as_echo "#define HAVE_LIBUSB 1" >>confdefs.h fi if test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes"; then SNDFILE_TRUE= SNDFILE_FALSE='#' else SNDFILE_TRUE='#' SNDFILE_FALSE= fi if test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"; then USB_TRUE= USB_FALSE='#' else USB_TRUE='#' USB_FALSE= fi if test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes" || test "${test_enable}" = "yes"; then SBC_TRUE= SBC_FALSE='#' else SBC_TRUE='#' SBC_FALSE= fi if test "${alsa_enable}" = "yes" && test "${alsa_found}" = "yes"; then ALSA_TRUE= ALSA_FALSE='#' else ALSA_TRUE='#' ALSA_FALSE= fi if test "${gstreamer_enable}" = "yes" && test "${gstreamer_found}" = "yes"; then GSTREAMER_TRUE= GSTREAMER_FALSE='#' else GSTREAMER_TRUE='#' GSTREAMER_FALSE= fi if test "${audio_enable}" = "yes"; then AUDIOPLUGIN_TRUE= AUDIOPLUGIN_FALSE='#' else AUDIOPLUGIN_TRUE='#' AUDIOPLUGIN_FALSE= fi if test "${input_enable}" = "yes"; then INPUTPLUGIN_TRUE= INPUTPLUGIN_FALSE='#' else INPUTPLUGIN_TRUE='#' INPUTPLUGIN_FALSE= fi if test "${serial_enable}" = "yes"; then SERIALPLUGIN_TRUE= SERIALPLUGIN_FALSE='#' else SERIALPLUGIN_TRUE='#' SERIALPLUGIN_FALSE= fi if test "${network_enable}" = "yes"; then NETWORKPLUGIN_TRUE= NETWORKPLUGIN_FALSE='#' else NETWORKPLUGIN_TRUE='#' NETWORKPLUGIN_FALSE= fi if test "${sap_enable}" = "yes"; then SAPPLUGIN_TRUE= SAPPLUGIN_FALSE='#' else SAPPLUGIN_TRUE='#' SAPPLUGIN_FALSE= fi if test "${service_enable}" = "yes"; then SERVICEPLUGIN_TRUE= SERVICEPLUGIN_FALSE='#' else SERVICEPLUGIN_TRUE='#' SERVICEPLUGIN_FALSE= fi if test "${health_enable}" = "yes"; then HEALTHPLUGIN_TRUE= HEALTHPLUGIN_FALSE='#' else HEALTHPLUGIN_TRUE='#' HEALTHPLUGIN_FALSE= fi if test "${health_enable}" = "yes"; then MCAP_TRUE= MCAP_FALSE='#' else MCAP_TRUE='#' MCAP_FALSE= fi if test "${hal_enable}" = "yes"; then HAL_TRUE= HAL_FALSE='#' else HAL_TRUE='#' HAL_FALSE= fi if test "${readline_found}" = "yes"; then READLINE_TRUE= READLINE_FALSE='#' else READLINE_TRUE='#' READLINE_FALSE= fi if test "${pnat_enable}" = "yes"; then PNATPLUGIN_TRUE= PNATPLUGIN_FALSE='#' else PNATPLUGIN_TRUE='#' PNATPLUGIN_FALSE= fi if test "${hidd_enable}" = "yes"; then HIDD_TRUE= HIDD_FALSE='#' else HIDD_TRUE='#' HIDD_FALSE= fi if test "${pand_enable}" = "yes"; then PAND_TRUE= PAND_FALSE='#' else PAND_TRUE='#' PAND_FALSE= fi if test "${dund_enable}" = "yes"; then DUND_TRUE= DUND_FALSE='#' else DUND_TRUE='#' DUND_FALSE= fi if test "${cups_enable}" = "yes"; then CUPS_TRUE= CUPS_FALSE='#' else CUPS_TRUE='#' CUPS_FALSE= fi if test "${test_enable}" = "yes" && test "${check_found}" = "yes"; then TEST_TRUE= TEST_FALSE='#' else TEST_TRUE='#' TEST_FALSE= fi if test "${tools_enable}" = "yes"; then TOOLS_TRUE= TOOLS_FALSE='#' else TOOLS_TRUE='#' TOOLS_FALSE= fi if test "${bccmd_enable}" = "yes"; then BCCMD_TRUE= BCCMD_FALSE='#' else BCCMD_TRUE='#' BCCMD_FALSE= fi if test "${pcmcia_enable}" = "yes"; then PCMCIA_TRUE= PCMCIA_FALSE='#' else PCMCIA_TRUE='#' PCMCIA_FALSE= fi if test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes" && test "${udev_found}" = "yes"; then HID2HCI_TRUE= HID2HCI_FALSE='#' else HID2HCI_TRUE='#' HID2HCI_FALSE= fi if test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes"; then DFUTOOL_TRUE= DFUTOOL_FALSE='#' else DFUTOOL_TRUE='#' DFUTOOL_FALSE= fi if test "${datafiles_enable}" = "yes"; then DATAFILES_TRUE= DATAFILES_FALSE='#' else DATAFILES_TRUE='#' DATAFILES_FALSE= fi if test "${maemo6_enable}" = "yes"; then MAEMO6PLUGIN_TRUE= MAEMO6PLUGIN_FALSE='#' else MAEMO6PLUGIN_TRUE='#' MAEMO6PLUGIN_FALSE= fi if test "${dbusoob_enable}" = "yes"; then DBUSOOBPLUGIN_TRUE= DBUSOOBPLUGIN_FALSE='#' else DBUSOOBPLUGIN_TRUE='#' DBUSOOBPLUGIN_FALSE= fi if test "${wiimote_enable}" = "yes"; then WIIMOTEPLUGIN_TRUE= WIIMOTEPLUGIN_FALSE='#' else WIIMOTEPLUGIN_TRUE='#' WIIMOTEPLUGIN_FALSE= fi if test "${gatt_enable}" = "yes"; then GATTMODULES_TRUE= GATTMODULES_FALSE='#' else GATTMODULES_TRUE='#' GATTMODULES_FALSE= fi # Check whether --with-systemdunitdir was given. if test "${with_systemdunitdir+set}" = set; then : withval=$with_systemdunitdir; path_systemdunit=${withval} else path_systemdunit="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`" fi if (test -n "${path_systemdunit}"); then SYSTEMD_UNITDIR="${path_systemdunit}" fi if test -n "${path_systemdunit}"; then SYSTEMD_TRUE= SYSTEMD_FALSE='#' else SYSTEMD_TRUE='#' SYSTEMD_FALSE= fi ac_config_files="$ac_config_files Makefile doc/version.xml src/bluetoothd.8 src/bluetooth.service bluez.pc" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SNDFILE_TRUE}" && test -z "${SNDFILE_FALSE}"; then as_fn_error $? "conditional \"SNDFILE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${USB_TRUE}" && test -z "${USB_FALSE}"; then as_fn_error $? "conditional \"USB\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SBC_TRUE}" && test -z "${SBC_FALSE}"; then as_fn_error $? "conditional \"SBC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${ALSA_TRUE}" && test -z "${ALSA_FALSE}"; then as_fn_error $? "conditional \"ALSA\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${GSTREAMER_TRUE}" && test -z "${GSTREAMER_FALSE}"; then as_fn_error $? "conditional \"GSTREAMER\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${AUDIOPLUGIN_TRUE}" && test -z "${AUDIOPLUGIN_FALSE}"; then as_fn_error $? "conditional \"AUDIOPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${INPUTPLUGIN_TRUE}" && test -z "${INPUTPLUGIN_FALSE}"; then as_fn_error $? "conditional \"INPUTPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SERIALPLUGIN_TRUE}" && test -z "${SERIALPLUGIN_FALSE}"; then as_fn_error $? "conditional \"SERIALPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${NETWORKPLUGIN_TRUE}" && test -z "${NETWORKPLUGIN_FALSE}"; then as_fn_error $? "conditional \"NETWORKPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SAPPLUGIN_TRUE}" && test -z "${SAPPLUGIN_FALSE}"; then as_fn_error $? "conditional \"SAPPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SERVICEPLUGIN_TRUE}" && test -z "${SERVICEPLUGIN_FALSE}"; then as_fn_error $? "conditional \"SERVICEPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HEALTHPLUGIN_TRUE}" && test -z "${HEALTHPLUGIN_FALSE}"; then as_fn_error $? "conditional \"HEALTHPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${MCAP_TRUE}" && test -z "${MCAP_FALSE}"; then as_fn_error $? "conditional \"MCAP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HAL_TRUE}" && test -z "${HAL_FALSE}"; then as_fn_error $? "conditional \"HAL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${READLINE_TRUE}" && test -z "${READLINE_FALSE}"; then as_fn_error $? "conditional \"READLINE\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PNATPLUGIN_TRUE}" && test -z "${PNATPLUGIN_FALSE}"; then as_fn_error $? "conditional \"PNATPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HIDD_TRUE}" && test -z "${HIDD_FALSE}"; then as_fn_error $? "conditional \"HIDD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PAND_TRUE}" && test -z "${PAND_FALSE}"; then as_fn_error $? "conditional \"PAND\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DUND_TRUE}" && test -z "${DUND_FALSE}"; then as_fn_error $? "conditional \"DUND\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${CUPS_TRUE}" && test -z "${CUPS_FALSE}"; then as_fn_error $? "conditional \"CUPS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${TEST_TRUE}" && test -z "${TEST_FALSE}"; then as_fn_error $? "conditional \"TEST\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${TOOLS_TRUE}" && test -z "${TOOLS_FALSE}"; then as_fn_error $? "conditional \"TOOLS\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${BCCMD_TRUE}" && test -z "${BCCMD_FALSE}"; then as_fn_error $? "conditional \"BCCMD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${PCMCIA_TRUE}" && test -z "${PCMCIA_FALSE}"; then as_fn_error $? "conditional \"PCMCIA\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${HID2HCI_TRUE}" && test -z "${HID2HCI_FALSE}"; then as_fn_error $? "conditional \"HID2HCI\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DFUTOOL_TRUE}" && test -z "${DFUTOOL_FALSE}"; then as_fn_error $? "conditional \"DFUTOOL\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DATAFILES_TRUE}" && test -z "${DATAFILES_FALSE}"; then as_fn_error $? "conditional \"DATAFILES\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${MAEMO6PLUGIN_TRUE}" && test -z "${MAEMO6PLUGIN_FALSE}"; then as_fn_error $? "conditional \"MAEMO6PLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${DBUSOOBPLUGIN_TRUE}" && test -z "${DBUSOOBPLUGIN_FALSE}"; then as_fn_error $? "conditional \"DBUSOOBPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${WIIMOTEPLUGIN_TRUE}" && test -z "${WIIMOTEPLUGIN_FALSE}"; then as_fn_error $? "conditional \"WIIMOTEPLUGIN\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${GATTMODULES_TRUE}" && test -z "${GATTMODULES_FALSE}"; then as_fn_error $? "conditional \"GATTMODULES\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${SYSTEMD_TRUE}" && test -z "${SYSTEMD_FALSE}"; then as_fn_error $? "conditional \"SYSTEMD\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by bluez $as_me 4.101, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ bluez config.status 4.101 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" # The HP-UX ksh and POSIX shell print the target directory to stdout # if CDPATH is set. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH sed_quote_subst='$sed_quote_subst' double_quote_subst='$double_quote_subst' delay_variable_subst='$delay_variable_subst' enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`' macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`' macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`' enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`' pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`' enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`' SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`' ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`' PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`' host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`' host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`' host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`' build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`' build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`' build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`' SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`' Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`' GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`' EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`' FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`' LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`' NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`' LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`' max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`' ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`' exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`' lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`' lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`' lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`' lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`' lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`' reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`' reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`' OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`' deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`' file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`' file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`' want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`' DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`' sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`' AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`' AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`' archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`' STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`' RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`' old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`' old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`' old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`' lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`' CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`' CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`' compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`' GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`' lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`' nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`' lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`' objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`' MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`' lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`' lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`' need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`' MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`' DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`' NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`' LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`' OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`' OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`' libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`' shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`' extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`' enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`' export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`' whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`' compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`' old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`' old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`' archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`' archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`' module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`' module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`' with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`' allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`' no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`' hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`' hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`' hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`' hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`' hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`' hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`' hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`' inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`' link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`' always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`' export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`' exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`' include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`' prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`' postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`' file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`' variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`' need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`' need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`' version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`' runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`' shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`' libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`' library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`' soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`' install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`' postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`' postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`' finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`' finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`' hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`' sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`' sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`' hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`' enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`' enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`' enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`' old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`' striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`' LTCC='$LTCC' LTCFLAGS='$LTCFLAGS' compiler='$compiler_DEFAULT' # A function that is used when there is no print builtin or printf. func_fallback_echo () { eval 'cat <<_LTECHO_EOF \$1 _LTECHO_EOF' } # Quote evaled strings. for var in SHELL \ ECHO \ PATH_SEPARATOR \ SED \ GREP \ EGREP \ FGREP \ LD \ NM \ LN_S \ lt_SP2NL \ lt_NL2SP \ reload_flag \ OBJDUMP \ deplibs_check_method \ file_magic_cmd \ file_magic_glob \ want_nocaseglob \ DLLTOOL \ sharedlib_from_linklib_cmd \ AR \ AR_FLAGS \ archiver_list_spec \ STRIP \ RANLIB \ CC \ CFLAGS \ compiler \ lt_cv_sys_global_symbol_pipe \ lt_cv_sys_global_symbol_to_cdecl \ lt_cv_sys_global_symbol_to_c_name_address \ lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \ nm_file_list_spec \ lt_prog_compiler_no_builtin_flag \ lt_prog_compiler_pic \ lt_prog_compiler_wl \ lt_prog_compiler_static \ lt_cv_prog_compiler_c_o \ need_locks \ MANIFEST_TOOL \ DSYMUTIL \ NMEDIT \ LIPO \ OTOOL \ OTOOL64 \ shrext_cmds \ export_dynamic_flag_spec \ whole_archive_flag_spec \ compiler_needs_object \ with_gnu_ld \ allow_undefined_flag \ no_undefined_flag \ hardcode_libdir_flag_spec \ hardcode_libdir_separator \ exclude_expsyms \ include_expsyms \ file_list_spec \ variables_saved_for_relink \ libname_spec \ library_names_spec \ soname_spec \ install_override_mode \ finish_eval \ old_striplib \ striplib; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done # Double-quote double-evaled strings. for var in reload_cmds \ old_postinstall_cmds \ old_postuninstall_cmds \ old_archive_cmds \ extract_expsyms_cmds \ old_archive_from_new_cmds \ old_archive_from_expsyms_cmds \ archive_cmds \ archive_expsym_cmds \ module_cmds \ module_expsym_cmds \ export_symbols_cmds \ prelink_cmds \ postlink_cmds \ postinstall_cmds \ postuninstall_cmds \ finish_cmds \ sys_lib_search_path_spec \ sys_lib_dlsearch_path_spec; do case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in *[\\\\\\\`\\"\\\$]*) eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\"" ;; *) eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\"" ;; esac done ac_aux_dir='$ac_aux_dir' xsi_shell='$xsi_shell' lt_shell_append='$lt_shell_append' # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes INIT. if test -n "\${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi PACKAGE='$PACKAGE' VERSION='$VERSION' TIMESTAMP='$TIMESTAMP' RM='$RM' ofile='$ofile' _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "doc/version.xml") CONFIG_FILES="$CONFIG_FILES doc/version.xml" ;; "src/bluetoothd.8") CONFIG_FILES="$CONFIG_FILES src/bluetoothd.8" ;; "src/bluetooth.service") CONFIG_FILES="$CONFIG_FILES src/bluetooth.service" ;; "bluez.pc") CONFIG_FILES="$CONFIG_FILES bluez.pc" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Autoconf 2.62 quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named `Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running `make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # When using ansi2knr, U may be empty or an underscore; expand it U=`sed -n 's/^U = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; "libtool":C) # See if we are running on zsh, and set the options which allow our # commands through without removal of \ escapes. if test -n "${ZSH_VERSION+set}" ; then setopt NO_GLOB_SUBST fi cfgfile="${ofile}T" trap "$RM \"$cfgfile\"; exit 1" 1 2 15 $RM "$cfgfile" cat <<_LT_EOF >> "$cfgfile" #! $SHELL # `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services. # Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION # Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`: # NOTE: Changes made to this file will be lost: look at ltmain.sh. # # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, # 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # Written by Gordon Matzigkeit, 1996 # # This file is part of GNU Libtool. # # GNU Libtool is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # As a special exception to the GNU General Public License, # if you distribute this file as part of a program or library that # is built using GNU Libtool, you may include this file under the # same distribution terms that you use for the rest of that program. # # GNU Libtool 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with GNU Libtool; see the file COPYING. If not, a copy # can be downloaded from http://www.gnu.org/licenses/gpl.html, or # obtained by writing to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # The names of the tagged configurations supported by this script. available_tags="" # ### BEGIN LIBTOOL CONFIG # Whether or not to build static libraries. build_old_libs=$enable_static # Which release of libtool.m4 was used? macro_version=$macro_version macro_revision=$macro_revision # Whether or not to build shared libraries. build_libtool_libs=$enable_shared # What type of objects to build. pic_mode=$pic_mode # Whether or not to optimize for fast installation. fast_install=$enable_fast_install # Shell to use when invoking shell scripts. SHELL=$lt_SHELL # An echo program that protects backslashes. ECHO=$lt_ECHO # The PATH separator for the build system. PATH_SEPARATOR=$lt_PATH_SEPARATOR # The host system. host_alias=$host_alias host=$host host_os=$host_os # The build system. build_alias=$build_alias build=$build build_os=$build_os # A sed program that does not truncate output. SED=$lt_SED # Sed that helps us avoid accidentally triggering echo(1) options like -n. Xsed="\$SED -e 1s/^X//" # A grep program that handles long lines. GREP=$lt_GREP # An ERE matcher. EGREP=$lt_EGREP # A literal string matcher. FGREP=$lt_FGREP # A BSD- or MS-compatible name lister. NM=$lt_NM # Whether we need soft or hard links. LN_S=$lt_LN_S # What is the maximum length of a command? max_cmd_len=$max_cmd_len # Object file suffix (normally "o"). objext=$ac_objext # Executable file suffix (normally ""). exeext=$exeext # whether the shell understands "unset". lt_unset=$lt_unset # turn spaces into newlines. SP2NL=$lt_lt_SP2NL # turn newlines into spaces. NL2SP=$lt_lt_NL2SP # convert \$build file names to \$host format. to_host_file_cmd=$lt_cv_to_host_file_cmd # convert \$build files to toolchain format. to_tool_file_cmd=$lt_cv_to_tool_file_cmd # An object symbol dumper. OBJDUMP=$lt_OBJDUMP # Method to check whether dependent libraries are shared objects. deplibs_check_method=$lt_deplibs_check_method # Command to use when deplibs_check_method = "file_magic". file_magic_cmd=$lt_file_magic_cmd # How to find potential files when deplibs_check_method = "file_magic". file_magic_glob=$lt_file_magic_glob # Find potential files using nocaseglob when deplibs_check_method = "file_magic". want_nocaseglob=$lt_want_nocaseglob # DLL creation program. DLLTOOL=$lt_DLLTOOL # Command to associate shared and link libraries. sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd # The archiver. AR=$lt_AR # Flags to create an archive. AR_FLAGS=$lt_AR_FLAGS # How to feed a file listing to the archiver. archiver_list_spec=$lt_archiver_list_spec # A symbol stripping program. STRIP=$lt_STRIP # Commands used to install an old-style archive. RANLIB=$lt_RANLIB old_postinstall_cmds=$lt_old_postinstall_cmds old_postuninstall_cmds=$lt_old_postuninstall_cmds # Whether to use a lock for old archive extraction. lock_old_archive_extraction=$lock_old_archive_extraction # A C compiler. LTCC=$lt_CC # LTCC compiler flags. LTCFLAGS=$lt_CFLAGS # Take the output of nm and produce a listing of raw symbols and C names. global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe # Transform the output of nm in a proper C declaration. global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl # Transform the output of nm in a C name address pair. global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address # Transform the output of nm in a C name address pair when lib prefix is needed. global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix # Specify filename containing input files for \$NM. nm_file_list_spec=$lt_nm_file_list_spec # The root where to search for dependent libraries,and in which our libraries should be installed. lt_sysroot=$lt_sysroot # The name of the directory that contains temporary libtool files. objdir=$objdir # Used to examine libraries when file_magic_cmd begins with "file". MAGIC_CMD=$MAGIC_CMD # Must we lock files when doing compilation? need_locks=$lt_need_locks # Manifest tool. MANIFEST_TOOL=$lt_MANIFEST_TOOL # Tool to manipulate archived DWARF debug symbol files on Mac OS X. DSYMUTIL=$lt_DSYMUTIL # Tool to change global to local symbols on Mac OS X. NMEDIT=$lt_NMEDIT # Tool to manipulate fat objects and archives on Mac OS X. LIPO=$lt_LIPO # ldd/readelf like tool for Mach-O binaries on Mac OS X. OTOOL=$lt_OTOOL # ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4. OTOOL64=$lt_OTOOL64 # Old archive suffix (normally "a"). libext=$libext # Shared library suffix (normally ".so"). shrext_cmds=$lt_shrext_cmds # The commands to extract the exported symbol list from a shared archive. extract_expsyms_cmds=$lt_extract_expsyms_cmds # Variables whose values should be saved in libtool wrapper scripts and # restored at link time. variables_saved_for_relink=$lt_variables_saved_for_relink # Do we need the "lib" prefix for modules? need_lib_prefix=$need_lib_prefix # Do we need a version for libraries? need_version=$need_version # Library versioning type. version_type=$version_type # Shared library runtime path variable. runpath_var=$runpath_var # Shared library path variable. shlibpath_var=$shlibpath_var # Is shlibpath searched before the hard-coded library search path? shlibpath_overrides_runpath=$shlibpath_overrides_runpath # Format of library name prefix. libname_spec=$lt_libname_spec # List of archive names. First name is the real one, the rest are links. # The last name is the one that the linker finds with -lNAME library_names_spec=$lt_library_names_spec # The coded name of the library, if different from the real name. soname_spec=$lt_soname_spec # Permission mode override for installation of shared libraries. install_override_mode=$lt_install_override_mode # Command to use after installation of a shared archive. postinstall_cmds=$lt_postinstall_cmds # Command to use after uninstallation of a shared archive. postuninstall_cmds=$lt_postuninstall_cmds # Commands used to finish a libtool library installation in a directory. finish_cmds=$lt_finish_cmds # As "finish_cmds", except a single script fragment to be evaled but # not shown. finish_eval=$lt_finish_eval # Whether we should hardcode library paths into libraries. hardcode_into_libs=$hardcode_into_libs # Compile-time system search path for libraries. sys_lib_search_path_spec=$lt_sys_lib_search_path_spec # Run-time system search path for libraries. sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec # Whether dlopen is supported. dlopen_support=$enable_dlopen # Whether dlopen of programs is supported. dlopen_self=$enable_dlopen_self # Whether dlopen of statically linked programs is supported. dlopen_self_static=$enable_dlopen_self_static # Commands to strip libraries. old_striplib=$lt_old_striplib striplib=$lt_striplib # The linker used to build libraries. LD=$lt_LD # How to create reloadable object files. reload_flag=$lt_reload_flag reload_cmds=$lt_reload_cmds # Commands used to build an old-style archive. old_archive_cmds=$lt_old_archive_cmds # A language specific compiler. CC=$lt_compiler # Is the compiler the GNU compiler? with_gcc=$GCC # Compiler flag to turn off builtin functions. no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag # Additional compiler flags for building library objects. pic_flag=$lt_lt_prog_compiler_pic # How to pass a linker flag through the compiler. wl=$lt_lt_prog_compiler_wl # Compiler flag to prevent dynamic linking. link_static_flag=$lt_lt_prog_compiler_static # Does compiler simultaneously support -c and -o options? compiler_c_o=$lt_lt_cv_prog_compiler_c_o # Whether or not to add -lc for building shared libraries. build_libtool_need_lc=$archive_cmds_need_lc # Whether or not to disallow shared libs when runtime libs are static. allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes # Compiler flag to allow reflexive dlopens. export_dynamic_flag_spec=$lt_export_dynamic_flag_spec # Compiler flag to generate shared objects directly from archives. whole_archive_flag_spec=$lt_whole_archive_flag_spec # Whether the compiler copes with passing no objects directly. compiler_needs_object=$lt_compiler_needs_object # Create an old-style archive from a shared archive. old_archive_from_new_cmds=$lt_old_archive_from_new_cmds # Create a temporary old-style archive to link instead of a shared archive. old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds # Commands used to build a shared archive. archive_cmds=$lt_archive_cmds archive_expsym_cmds=$lt_archive_expsym_cmds # Commands used to build a loadable module if different from building # a shared archive. module_cmds=$lt_module_cmds module_expsym_cmds=$lt_module_expsym_cmds # Whether we are building with GNU ld or not. with_gnu_ld=$lt_with_gnu_ld # Flag that allows shared libraries with undefined symbols to be built. allow_undefined_flag=$lt_allow_undefined_flag # Flag that enforces no undefined symbols. no_undefined_flag=$lt_no_undefined_flag # Flag to hardcode \$libdir into a binary during linking. # This must work even if \$libdir does not exist hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec # Whether we need a single "-rpath" flag with a separated argument. hardcode_libdir_separator=$lt_hardcode_libdir_separator # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary. hardcode_direct=$hardcode_direct # Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes # DIR into the resulting binary and the resulting library dependency is # "absolute",i.e impossible to change by setting \${shlibpath_var} if the # library is relocated. hardcode_direct_absolute=$hardcode_direct_absolute # Set to "yes" if using the -LDIR flag during linking hardcodes DIR # into the resulting binary. hardcode_minus_L=$hardcode_minus_L # Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR # into the resulting binary. hardcode_shlibpath_var=$hardcode_shlibpath_var # Set to "yes" if building a shared library automatically hardcodes DIR # into the library and all subsequent libraries and executables linked # against it. hardcode_automatic=$hardcode_automatic # Set to yes if linker adds runtime paths of dependent libraries # to runtime path list. inherit_rpath=$inherit_rpath # Whether libtool must link a program against all its dependency libraries. link_all_deplibs=$link_all_deplibs # Set to "yes" if exported symbols are required. always_export_symbols=$always_export_symbols # The commands to list exported symbols. export_symbols_cmds=$lt_export_symbols_cmds # Symbols that should not be listed in the preloaded symbols. exclude_expsyms=$lt_exclude_expsyms # Symbols that must always be exported. include_expsyms=$lt_include_expsyms # Commands necessary for linking programs (against libraries) with templates. prelink_cmds=$lt_prelink_cmds # Commands necessary for finishing linking programs. postlink_cmds=$lt_postlink_cmds # Specify filename containing input files. file_list_spec=$lt_file_list_spec # How to hardcode a shared library path into an executable. hardcode_action=$hardcode_action # ### END LIBTOOL CONFIG _LT_EOF case $host_os in aix3*) cat <<\_LT_EOF >> "$cfgfile" # AIX sometimes has problems with the GCC collect2 program. For some # reason, if we set the COLLECT_NAMES environment variable, the problems # vanish in a puff of smoke. if test "X${COLLECT_NAMES+set}" != Xset; then COLLECT_NAMES= export COLLECT_NAMES fi _LT_EOF ;; esac ltmain="$ac_aux_dir/ltmain.sh" # We use sed instead of cat because bash on DJGPP gets confused if # if finds mixed CR/LF and LF-only lines. Since sed operates in # text mode, it properly converts lines to CR/LF. This bash problem # is reportedly fixed, but why not run on old versions too? sed '$q' "$ltmain" >> "$cfgfile" \ || (rm -f "$cfgfile"; exit 1) if test x"$xsi_shell" = xyes; then sed -e '/^func_dirname ()$/,/^} # func_dirname /c\ func_dirname ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ } # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_basename ()$/,/^} # func_basename /c\ func_basename ()\ {\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\ func_dirname_and_basename ()\ {\ \ case ${1} in\ \ */*) func_dirname_result="${1%/*}${2}" ;;\ \ * ) func_dirname_result="${3}" ;;\ \ esac\ \ func_basename_result="${1##*/}"\ } # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_stripname ()$/,/^} # func_stripname /c\ func_stripname ()\ {\ \ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\ \ # positional parameters, so assign one to ordinary parameter first.\ \ func_stripname_result=${3}\ \ func_stripname_result=${func_stripname_result#"${1}"}\ \ func_stripname_result=${func_stripname_result%"${2}"}\ } # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\ func_split_long_opt ()\ {\ \ func_split_long_opt_name=${1%%=*}\ \ func_split_long_opt_arg=${1#*=}\ } # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\ func_split_short_opt ()\ {\ \ func_split_short_opt_arg=${1#??}\ \ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\ } # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\ func_lo2o ()\ {\ \ case ${1} in\ \ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\ \ *) func_lo2o_result=${1} ;;\ \ esac\ } # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_xform ()$/,/^} # func_xform /c\ func_xform ()\ {\ func_xform_result=${1%.*}.lo\ } # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_arith ()$/,/^} # func_arith /c\ func_arith ()\ {\ func_arith_result=$(( $* ))\ } # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_len ()$/,/^} # func_len /c\ func_len ()\ {\ func_len_result=${#1}\ } # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$lt_shell_append" = xyes; then sed -e '/^func_append ()$/,/^} # func_append /c\ func_append ()\ {\ eval "${1}+=\\${2}"\ } # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\ func_append_quoted ()\ {\ \ func_quote_for_eval "${2}"\ \ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\ } # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: # Save a `func_append' function call where possible by direct use of '+=' sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: else # Save a `func_append' function call even when '+=' is not available sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \ && mv -f "$cfgfile.tmp" "$cfgfile" \ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp") test 0 -eq $? || _lt_function_replace_fail=: fi if test x"$_lt_function_replace_fail" = x":"; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5 $as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;} fi mv -f "$cfgfile" "$ofile" || (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile") chmod +x "$ofile" ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi bluez-4.101/COPYING0000644000000000000000000004312611071665350010574 00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. bluez-4.101/Makefile.am0000644000000000000000000003167111771117441011577 00000000000000 AM_MAKEFLAGS = --no-print-directory lib_LTLIBRARIES = noinst_LIBRARIES = noinst_LTLIBRARIES = bin_PROGRAMS = sbin_PROGRAMS = noinst_PROGRAMS = dist_man_MANS = dist_noinst_MANS = CLEANFILES = EXTRA_DIST = includedir = @includedir@/bluetooth include_HEADERS = AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS) AM_LDFLAGS = $(MISC_LDFLAGS) if DATAFILES dbusdir = $(sysconfdir)/dbus-1/system.d dbusservicedir = $(datadir)/dbus-1/system-services dbus_DATA = src/bluetooth.conf dbusservice_DATA = src/org.bluez.service confdir = $(sysconfdir)/bluetooth conf_DATA = statedir = $(localstatedir)/lib/bluetooth state_DATA = if SYSTEMD systemdunitdir = @SYSTEMD_UNITDIR@ systemdunit_DATA = src/bluetooth.service endif endif plugindir = $(libdir)/bluetooth/plugins if MAINTAINER_MODE build_plugindir = $(abs_top_srcdir)/plugins/.libs else build_plugindir = $(plugindir) endif plugin_LTLIBRARIES = lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h lib/mgmt.h \ lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h lib/uuid.h \ lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h lib/a2mp.h local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file))) BUILT_SOURCES = $(local_headers) src/builtin.h include_HEADERS += $(lib_headers) lib_LTLIBRARIES += lib/libbluetooth.la lib_libbluetooth_la_SOURCES = $(lib_headers) \ lib/bluetooth.c lib/hci.c lib/sdp.c lib/uuid.c lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 16:0:13 lib_libbluetooth_la_DEPENDENCIES = $(local_headers) noinst_LTLIBRARIES += lib/libbluetooth-private.la lib_libbluetooth_private_la_SOURCES = $(lib_libbluetooth_la_SOURCES) if SBC noinst_LTLIBRARIES += sbc/libsbc.la sbc_libsbc_la_SOURCES = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h sbc/sbc_tables.h \ sbc/sbc_primitives.h sbc/sbc_primitives.c \ sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \ sbc/sbc_primitives_iwmmxt.h sbc/sbc_primitives_iwmmxt.c \ sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \ sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c sbc_libsbc_la_CFLAGS = $(AM_CFLAGS) -finline-functions -fgcse-after-reload \ -funswitch-loops -funroll-loops noinst_PROGRAMS += sbc/sbcinfo sbc/sbcdec sbc/sbcenc sbc_sbcdec_SOURCES = sbc/sbcdec.c sbc/formats.h sbc_sbcdec_LDADD = sbc/libsbc.la sbc_sbcenc_SOURCES = sbc/sbcenc.c sbc/formats.h sbc_sbcenc_LDADD = sbc/libsbc.la if SNDFILE noinst_PROGRAMS += sbc/sbctester sbc_sbctester_LDADD = @SNDFILE_LIBS@ -lm sbc_sbctest_CFLAGS = $(AM_CFLAGS) @SNDFILE_CFLAGS@ endif endif attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \ attrib/gatt.h attrib/gatt.c \ attrib/gattrib.h attrib/gattrib.c attrib/client.h \ attrib/client.c attrib/gatt-service.h attrib/gatt-service.c gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \ gdbus/object.c gdbus/polkit.c btio_sources = btio/btio.h btio/btio.c builtin_modules = builtin_sources = builtin_nodist = mcap_sources = if MCAP mcap_sources += health/mcap_lib.h health/mcap_internal.h \ health/mcap.h health/mcap.c \ health/mcap_sync.c endif if PNATPLUGIN builtin_modules += pnat builtin_sources += plugins/pnat.c endif if AUDIOPLUGIN builtin_modules += audio builtin_sources += audio/main.c \ audio/manager.h audio/manager.c \ audio/gateway.h audio/gateway.c \ audio/headset.h audio/headset.c \ audio/control.h audio/control.c \ audio/avctp.h audio/avctp.c \ audio/avrcp.h audio/avrcp.c \ audio/device.h audio/device.c \ audio/source.h audio/source.c \ audio/sink.h audio/sink.c \ audio/a2dp.h audio/a2dp.c \ audio/avdtp.h audio/avdtp.c \ audio/ipc.h audio/ipc.c \ audio/unix.h audio/unix.c \ audio/media.h audio/media.c \ audio/transport.h audio/transport.c \ audio/telephony.h audio/a2dp-codecs.h builtin_nodist += audio/telephony.c noinst_LIBRARIES += audio/libtelephony.a audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \ audio/telephony-maemo5.c audio/telephony-ofono.c \ audio/telephony-maemo6.c endif if SAPPLUGIN builtin_modules += sap builtin_sources += sap/main.c \ sap/manager.h sap/manager.c \ sap/server.h sap/server.c \ sap/sap.h builtin_nodist += sap/sap.c noinst_LIBRARIES += sap/libsap.a sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c sap/sap-u8500.c endif if INPUTPLUGIN builtin_modules += input builtin_sources += input/main.c \ input/manager.h input/manager.c \ input/server.h input/server.c \ input/device.h input/device.c \ input/fakehid.c input/fakehid.h endif if SERIALPLUGIN builtin_modules += serial builtin_sources += serial/main.c \ serial/manager.h serial/manager.c \ serial/proxy.h serial/proxy.c \ serial/port.h serial/port.c endif if NETWORKPLUGIN builtin_modules += network builtin_sources += network/main.c \ network/manager.h network/manager.c \ network/common.h network/common.c \ network/server.h network/server.c \ network/connection.h network/connection.c endif if SERVICEPLUGIN builtin_modules += service builtin_sources += plugins/service.c endif if HEALTHPLUGIN builtin_modules += health builtin_sources += health/hdp_main.c health/hdp_types.h \ health/hdp_manager.h health/hdp_manager.c \ health/hdp.h health/hdp.c \ health/hdp_util.h health/hdp_util.c endif if GATTMODULES builtin_modules += thermometer alert time gatt_example proximity \ deviceinfo builtin_sources += thermometer/main.c \ thermometer/manager.h thermometer/manager.c \ thermometer/thermometer.h thermometer/thermometer.c \ alert/main.c alert/server.h alert/server.c \ time/main.c time/server.h time/server.c \ plugins/gatt-example.c \ proximity/main.c proximity/manager.h proximity/manager.c \ proximity/monitor.h proximity/monitor.c \ proximity/reporter.h proximity/reporter.c \ proximity/linkloss.h proximity/linkloss.c \ proximity/immalert.h proximity/immalert.c \ deviceinfo/main.c \ deviceinfo/manager.h deviceinfo/manager.c \ deviceinfo/deviceinfo.h deviceinfo/deviceinfo.c endif builtin_modules += hciops mgmtops builtin_sources += plugins/hciops.c plugins/mgmtops.c if HAL builtin_modules += hal builtin_sources += plugins/hal.c else builtin_modules += formfactor builtin_sources += plugins/formfactor.c endif EXTRA_DIST += plugins/hal.c plugins/formfactor.c builtin_modules += storage builtin_sources += plugins/storage.c builtin_modules += adaptername builtin_sources += plugins/adaptername.c if WIIMOTEPLUGIN builtin_modules += wiimote builtin_sources += plugins/wiimote.c endif if MAEMO6PLUGIN builtin_modules += maemo6 builtin_sources += plugins/maemo6.c endif if DBUSOOBPLUGIN builtin_modules += dbusoob builtin_sources += plugins/dbusoob.c endif if MAINTAINER_MODE plugin_LTLIBRARIES += plugins/external-dummy.la plugins_external_dummy_la_SOURCES = plugins/external-dummy.c plugins_external_dummy_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \ -no-undefined plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden endif sbin_PROGRAMS += src/bluetoothd src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \ $(attrib_sources) $(btio_sources) \ $(mcap_sources) src/bluetooth.ver \ src/main.c src/log.h src/log.c \ src/rfkill.c src/hcid.h src/sdpd.h \ src/sdpd-server.c src/sdpd-request.c \ src/sdpd-service.c src/sdpd-database.c \ src/attrib-server.h src/attrib-server.c \ src/sdp-xml.h src/sdp-xml.c \ src/sdp-client.h src/sdp-client.c \ src/textfile.h src/textfile.c \ src/glib-helper.h src/glib-helper.c \ src/oui.h src/oui.c src/uinput.h src/ppoll.h \ src/plugin.h src/plugin.c \ src/storage.h src/storage.c \ src/agent.h src/agent.c \ src/error.h src/error.c \ src/manager.h src/manager.c \ src/adapter.h src/adapter.c \ src/device.h src/device.c src/attio.h \ src/dbus-common.c src/dbus-common.h \ src/event.h src/event.c \ src/oob.h src/oob.c src/eir.h src/eir.c src_bluetoothd_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @DBUS_LIBS@ \ -ldl -lrt src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \ -Wl,--version-script=$(srcdir)/src/bluetooth.ver src_bluetoothd_DEPENDENCIES = lib/libbluetooth-private.la src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \ -DPLUGINDIR=\""$(build_plugindir)"\" src_bluetoothd_SHORTNAME = bluetoothd builtin_files = src/builtin.h $(builtin_nodist) nodist_src_bluetoothd_SOURCES = $(builtin_files) CLEANFILES += $(builtin_files) man_MANS = src/bluetoothd.8 if DATAFILES conf_DATA += src/main.conf endif EXTRA_DIST += src/genbuiltin src/bluetooth.conf src/org.bluez.service \ src/main.conf network/network.conf \ input/input.conf serial/serial.conf \ audio/audio.conf audio/telephony-dummy.c \ audio/telephony-maemo5.c audio/telephony-ofono.c \ audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c \ proximity/proximity.conf if ALSA alsadir = $(libdir)/alsa-lib alsa_LTLIBRARIES = audio/libasound_module_pcm_bluetooth.la \ audio/libasound_module_ctl_bluetooth.la audio_libasound_module_pcm_bluetooth_la_SOURCES = audio/pcm_bluetooth.c \ audio/rtp.h audio/ipc.h audio/ipc.c audio_libasound_module_pcm_bluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module \ -avoid-version audio_libasound_module_pcm_bluetooth_la_LIBADD = sbc/libsbc.la \ lib/libbluetooth-private.la @ALSA_LIBS@ audio_libasound_module_pcm_bluetooth_la_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@ audio_libasound_module_ctl_bluetooth_la_SOURCES = audio/ctl_bluetooth.c \ audio/rtp.h audio/ipc.h audio/ipc.c audio_libasound_module_ctl_bluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module \ -avoid-version audio_libasound_module_ctl_bluetooth_la_LIBADD = \ lib/libbluetooth-private.la @ALSA_LIBS@ audio_libasound_module_ctl_bluetooth_la_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@ if DATAFILES alsaconfdir = $(datadir)/alsa alsaconf_DATA = audio/bluetooth.conf endif endif if AUDIOPLUGIN if GSTREAMER gstreamerdir = $(libdir)/gstreamer-0.10 gstreamer_LTLIBRARIES = audio/libgstbluetooth.la audio_libgstbluetooth_la_SOURCES = audio/gstbluetooth.c audio/gstpragma.h \ audio/gstsbcenc.h audio/gstsbcenc.c \ audio/gstsbcdec.h audio/gstsbcdec.c \ audio/gstsbcparse.h audio/gstsbcparse.c \ audio/gstavdtpsink.h audio/gstavdtpsink.c \ audio/gsta2dpsink.h audio/gsta2dpsink.c \ audio/gstsbcutil.h audio/gstsbcutil.c \ audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \ audio/rtp.h audio/ipc.h audio/ipc.c audio_libgstbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version audio_libgstbluetooth_la_LIBADD = sbc/libsbc.la lib/libbluetooth-private.la \ @DBUS_LIBS@ @GSTREAMER_LIBS@ \ -lgstaudio-0.10 -lgstrtp-0.10 audio_libgstbluetooth_la_CFLAGS = -fvisibility=hidden -fno-strict-aliasing \ $(AM_CFLAGS) @DBUS_CFLAGS@ @GSTREAMER_CFLAGS@ endif endif EXTRA_DIST += audio/bluetooth.conf include Makefile.tools if DATAFILES rulesdir = @UDEV_DIR@/rules.d udev_files = if HID2HCI udev_files += scripts/bluetooth-hid2hci.rules endif if PCMCIA udevdir = @UDEV_DIR@ udev_files += scripts/bluetooth-serial.rules dist_udev_SCRIPTS = scripts/bluetooth_serial endif rules_DATA = $(foreach file,$(udev_files), scripts/97-$(notdir $(file))) endif CLEANFILES += $(rules_DATA) EXTRA_DIST += scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules EXTRA_DIST += doc/manager-api.txt \ doc/adapter-api.txt doc/device-api.txt \ doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \ doc/serial-api.txt doc/network-api.txt \ doc/input-api.txt doc/audio-api.txt doc/control-api.txt \ doc/hfp-api.txt doc/health-api.txt doc/sap-api.txt \ doc/media-api.txt doc/assigned-numbers.txt AM_YFLAGS = -d AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@ INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \ -I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus \ -I$(srcdir)/attrib -I$(srcdir)/btio -I$(srcdir)/tools \ -I$(builddir)/tools -I$(srcdir)/monitor if MCAP INCLUDES += -I$(builddir)/health endif unit_objects = if TEST unit_tests = unit/test-eir noinst_PROGRAMS += $(unit_tests) unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/glib-helper.c unit_test_eir_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @CHECK_LIBS@ unit_test_eir_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@ unit_objects += $(unit_test_eir_OBJECTS) else unit_tests = endif TESTS = $(unit_tests) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = bluez.pc DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles DISTCLEANFILES = $(pkgconfig_DATA) MAINTAINERCLEANFILES = Makefile.in \ aclocal.m4 configure config.h.in config.sub config.guess \ ltmain.sh depcomp compile missing install-sh mkinstalldirs ylwrap src/builtin.h: src/genbuiltin $(builtin_sources) $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@ audio/telephony.c: audio/@TELEPHONY_DRIVER@ $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@ sap/sap.c: sap/@SAP_DRIVER@ $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@ scripts/%.rules: $(AM_V_GEN)cp $(subst 97-,,$@) $@ $(lib_libbluetooth_la_OBJECTS): $(local_headers) lib/bluetooth/%.h: lib/%.h $(AM_V_at)$(MKDIR_P) lib/bluetooth $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@ clean-local: $(RM) -r lib/bluetooth bluez-4.101/doc/0000755000000000000000000000000011771120005010346 500000000000000bluez-4.101/doc/version.xml.in0000644000000000000000000000001211177424171013106 00000000000000@VERSION@ bluez-4.101/doc/sap-api.txt0000644000000000000000000000141211571052274012371 00000000000000BlueZ D-Bus Sim Access Profile API description *********************************** Copyright (C) 2010 ST-Ericsson SA Sim Access Profile hierarchy ============================ Service org.bluez Interface org.bluez.SimAccess Object path [variable prefix]/{hci0,hci1,...} Methods void Disconnect() Disconnects SAP client from the server. Possible errors: org.bluez.Error.Failed dict GetProperties() Return all properties for the interface. See the properties section for available properties. Possible Errors: org.bluez.Error.Failed Signals PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. Properties boolean Connected [readonly] Indicates if SAP client is connected to the server. bluez-4.101/doc/media-api.txt0000644000000000000000000001741411766125764012711 00000000000000BlueZ D-Bus Media API description ********************************* Media hierarchy =============== Service org.bluez Interface org.bluez.Media Object path [variable prefix]/{hci0,hci1,...} Methods void RegisterEndpoint(object endpoint, dict properties) Register a local end point to sender, the sender can register as many end points as it likes. Note: If the sender disconnects the end points are automatically unregistered. possible properties: string UUID: UUID of the profile which the endpoint is for. byte Codec: Assigned number of codec that the endpoint implements. The values should match the profile specification which is indicated by the UUID. array{byte} Capabilities: Capabilities blob, it is used as it is so the size and byte order must match. Possible Errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotSupported - emitted when interface for the end-point is disabled. void UnregisterEndpoint(object endpoint) Unregister sender end point. void RegisterPlayer(object player, dict properties, dict metadata) Register a media player object to sender, the sender can register as many objets as it likes. Note: If the sender disconnects its objects are automatically unregistered. Properties: string Equalizer: Possible values: "off" or "on" string Repeat: Possible values: "off", "singletrack", "alltracks" or "group" string Shuffle: Possible values: "off", "alltracks" or "group" string Scan: Possible values: "off", "alltracks" or "group" string Status: Possible values: "playing", "stopped", "paused", "forward-seek", "reverse-seek" or "error" uint32 Position Playback position in milliseconds Metadata: string Title: Track title name string Artist: Track artist name string Album: Track album name string Genre: Track genre name uint32 NumberOfTracks: Number of tracks in total uint32 Number: Track number uint32 Duration: Track duration in milliseconds Possible Errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotSupported void UnregisterPlayer(object player) Unregister sender media player. MediaPlayer hierarchy ===================== Service unique name Interface org.bluez.MediaPlayer Object path freely definable Methods void SetProperty(string property, variant value) Changes the value of the specified property. Only properties that are listed as read-write can be changed. On success this will emit a PropertyChanged signal. void Release() This method gets called when the service daemon unregisters the player which can then perform cleanup tasks. There is no need to unregister the player, because when this method gets called it has already been unregistered. Signals PropertyChanged(string setting, variant value) This signal indicates a changed value of the given property. TrackChanged(dict metadata) This signal indicates that current track has changed. All available metadata for the new track shall be set at once in the metadata argument. Metadata cannot be updated in parts, otherwise it will be interpreted as multiple track changes. Possible values: string Title: Track title name string Artist: Track artist name string Album: Track album name string Genre: Track genre name uint32 NumberOfTracks: Number of tracks in total uint32 Number: Track number uint32 Duration: Track duration in milliseconds Properties string Equalizer [readwrite] Possible values: "off" or "on" string Repeat [readwrite] Possible values: "off", "singletrack", "alltracks" or "group" string Shuffle [readwrite] Possible values: "off", "alltracks" or "group" string Scan [readwrite] Possible values: "off", "alltracks" or "group" string Status [readonly] Possible status: "playing", "stopped", "paused", "forward-seek", "reverse-seek" or "error" uint32 Position [readonly] Playback position in milliseconds. Changing the position may generate additional events that will be sent to the remote device. When position is 0 it means the track is starting and when it's greater than or equal to track's duration the track has ended. Note that even if duration is not available in metadata it's possible to signal its end by setting position to the maximum uint32 value. MediaEndpoint hierarchy ======================= Service unique name Interface org.bluez.MediaEndpoint Object path freely definable Methods void SetConfiguration(object transport, dict properties) Set configuration for the transport. array{byte} SelectConfiguration(array{byte} capabilities) Select preferable configuration from the supported capabilities. Returns a configuration which can be used to setup a transport. Note: There is no need to cache the selected configuration since on success the configuration is send back as parameter of SetConfiguration. void ClearConfiguration(object transport) Clear transport configuration. void Release() This method gets called when the service daemon unregisters the endpoint. An endpoint can use it to do cleanup tasks. There is no need to unregister the endpoint, because when this method gets called it has already been unregistered. MediaTransport hierarchy ======================== Service org.bluez Interface org.bluez.MediaTransport Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/fdX Methods dict GetProperties() Returns all properties for the interface. See the properties section for available properties. fd, uint16, uint16 Acquire(string accesstype) Acquire transport file descriptor and the MTU for read and write respectively. possible accesstype: "r" : Read only access "w" : Write only access "rw": Read and write access void Release(string accesstype) Releases file descriptor. void SetProperty(string name, variant value) Changes the value of the specified property. Only properties that are listed a read-write can be changed. On success this will emit a PropertyChanged signal. Signals void PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. Properties object Device [readonly] Device object which the transport is connected to. string UUID [readonly] UUID of the profile which the transport is for. byte Codec [readonly] Assigned number of codec that the transport support. The values should match the profile specification which is indicated by the UUID. array{byte} Configuration [readonly] Configuration blob, it is used as it is so the size and byte order must match. uint16 Delay [readwrite] Optional. Transport delay in 1/10 of millisecond, this property is only writeable when the transport was acquired by the sender. boolean NREC [readwrite] Optional. Indicates if echo cancelling and noise reduction functions are active in the transport, this property is only writeable when the transport was acquired by the sender. boolean InbandRingtone [readwrite] Optional. Indicates if the transport support sending ringtones, this property is only writeable when the transport was acquired by the sender. string Routing [readonly] Optional. Indicates where is the transport being routed Possible Values: "HCI" or "PCM" uint16 Volume [readwrite] Optional. Indicates volume level of the transport, this property is only writeable when the transport was acquired by the sender. Possible Values: 0-127 bluez-4.101/doc/input-api.txt0000644000000000000000000000201711376221745012753 00000000000000BlueZ D-Bus Input API description ********************************* Copyright (C) 2004-2010 Marcel Holtmann Input hierarchy =============== Service org.bluez Interface org.bluez.Input Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods void Connect() Connect to the input device. Possible errors: org.bluez.Error.AlreadyConnected org.bluez.Error.ConnectionAttemptFailed void Disconnect() Disconnect from the input device. To abort a connection attempt in case of errors or timeouts in the client it is fine to call this method. Possible errors: org.bluez.Error.Failed dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Possible Errors: org.bluez.Error.InvalidArguments Signals PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. Properties boolean Connected [readonly] Indicates if the device is connected. bluez-4.101/doc/adapter-api.txt0000644000000000000000000002034511766125764013247 00000000000000BlueZ D-Bus Adapter API description *********************************** Copyright (C) 2004-2010 Marcel Holtmann Copyright (C) 2005-2006 Johan Hedberg Copyright (C) 2005-2006 Claudio Takahasi Copyright (C) 2006-2007 Luiz von Dentz Adapter hierarchy ================= Service org.bluez Interface org.bluez.Adapter Object path [variable prefix]/{hci0,hci1,...} Methods dict GetProperties() Returns all properties for the adapter. See the properties section for available properties. Possible Errors: org.bluez.Error.NotReady void SetProperty(string name, variant value) Changes the value of the specified property. Only properties that are listed a read-write are changeable. On success this will emit a PropertyChanged signal. Possible Errors: org.bluez.Error.InvalidArguments void RequestSession() This method requests a client session that provides operational Bluetooth. A possible mode change must be confirmed by the user via the agent. Clients may request multiple sessions. All sessions are released when adapter's mode is changed to off state. Possible Errors: org.bluez.Error.Rejected void ReleaseSession() Release a previously requested session. It sets adapter to the mode in use on the moment of session request. SetProperty method call changes adapter's mode persistently, such that session release will not modify it. Possible Errors: org.bluez.Error.DoesNotExist void StartDiscovery() This method starts the device discovery session. This includes an inquiry procedure and remote device name resolving. Use StopDiscovery to release the sessions acquired. This process will start emitting DeviceFound and PropertyChanged "Discovering" signals. Possible errors: org.bluez.Error.NotReady org.bluez.Error.Failed void StopDiscovery() This method will cancel any previous StartDiscovery transaction. Note that a discovery procedure is shared between all discovery sessions thus calling StopDiscovery will only release a single session. Possible errors: org.bluez.Error.NotReady org.bluez.Error.Failed org.bluez.Error.NotAuthorized object FindDevice(string address) Returns the object path of device for given address. The device object needs to be first created via CreateDevice or CreatePairedDevice. Possible Errors: org.bluez.Error.DoesNotExist org.bluez.Error.InvalidArguments array{object} ListDevices() {deprecated} Returns list of device object paths. This method is deprecated, instead use the Devices Property to get the list of devices object paths. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.Failed org.bluez.Error.OutOfMemory object CreateDevice(string address) Creates a new object path for a remote device. This method will connect to the remote device and retrieve all SDP records. If the object for the remote device already exists this method will fail. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.Failed object CreatePairedDevice(string address, object agent, string capability) Creates a new object path for a remote device. This method will connect to the remote device and retrieve all SDP records and then initiate the pairing. If previously CreateDevice was used successfully, this method will only initiate the pairing. Compared to CreateDevice this method will fail if the pairing already exists, but not if the object path already has been created. This allows applications to use CreateDevice first and the if needed use CreatePairedDevice to initiate pairing. The agent object path is assumed to reside within the process (D-Bus connection instance) that calls this method. No separate registration procedure is needed for it and it gets automatically released once the pairing operation is complete. The capability parameter is the same as for the RegisterAgent method. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.Failed void CancelDeviceCreation(string address) Aborts either a CreateDevice call or a CreatePairedDevice call. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotInProgress void RemoveDevice(object device) This removes the remote device object at the given path. It will remove also the pairing information. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.Failed void RegisterAgent(object agent, string capability) This registers the adapter wide agent. The object path defines the path of the agent that will be called when user input is needed. If an application disconnects from the bus all of its registered agents will be removed. The capability parameter can have the values "DisplayOnly", "DisplayYesNo", "KeyboardOnly", "NoInputNoOutput" and "KeyboardDisplay" which reflects the input and output capabilities of the agent. If an empty string is used it will fallback to "DisplayYesNo". Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.AlreadyExists void UnregisterAgent(object agent) This unregisters the agent that has been previously registered. The object path parameter must match the same value that has been used on registration. Possible errors: org.bluez.Error.DoesNotExist Signals PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. DeviceFound(string address, dict values) This signal will be sent every time an inquiry result has been found by the service daemon. In general they only appear during a device discovery. The dictionary can contain basically the same values that are returned by the GetProperties method from the org.bluez.Device interface. In addition there can be values for the RSSI, the TX power level and Broadcaster role. DeviceDisappeared(string address) This signal will be sent when an inquiry session for a periodic discovery finishes and previously found devices are no longer in range or visible. DeviceCreated(object device) Parameter is object path of created device. DeviceRemoved(object device) Parameter is object path of removed device. Properties string Address [readonly] The Bluetooth device address. string Name [readwrite] The Bluetooth friendly name. This value can be changed and a PropertyChanged signal will be emitted. uint32 Class [readonly] The Bluetooth class of device. boolean Powered [readwrite] Switch an adapter on or off. This will also set the appropriate connectable state. boolean Discoverable [readwrite] Switch an adapter to discoverable or non-discoverable to either make it visible or hide it. This is a global setting and should only be used by the settings application. If the DiscoverableTimeout is set to a non-zero value then the system will set this value back to false after the timer expired. In case the adapter is switched off, setting this value will fail. When changing the Powered property the new state of this property will be updated via a PropertyChanged signal. boolean Pairable [readwrite] Switch an adapter to pairable or non-pairable. This is a global setting and should only be used by the settings application. Note that this property only affects incoming pairing requests. uint32 PairableTimeout [readwrite] The pairable timeout in seconds. A value of zero means that the timeout is disabled and it will stay in pairable mode forever. uint32 DiscoverableTimeout [readwrite] The discoverable timeout in seconds. A value of zero means that the timeout is disabled and it will stay in discoverable/limited mode forever. The default value for the discoverable timeout should be 180 seconds (3 minutes). boolean Discovering [readonly] Indicates that a device discovery procedure is active. array{object} Devices [readonly] List of device object paths. array{string} UUIDs [readonly] List of 128-bit UUIDs that represents the available local services. bluez-4.101/doc/health-api.txt0000644000000000000000000001073611766125764013077 00000000000000BlueZ D-Bus Health API description ********************************** Santiago Carot-Nemesio José Antonio Santos-Cadenas Elvis Pfützenreuter Health Device Profile hierarchy =============================== Service org.bluez Interface org.bluez.HealthManager Object path /org/bluez/ Methods: object CreateApplication(dict config) Returns the path of the new registered application. Dict is defined as below: { "DataType": uint16, (mandatory) "Role" : ("Source" or "Sink"), (mandatory) "Description" : string, (optional) "ChannelType" : ("Reliable" or "Streaming") (just for Sources, optional) } Application will be closed by the call or implicitly when the programs leaves the bus. Possible errors: org.bluez.Error.InvalidArguments void DestroyApplication(object application) Closes the HDP application identified by the object path. Also application will be closed if the process that started it leaves the bus. Only the creator of the application will be able to destroy it. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotFound org.bluez.Error.NotAllowed -------------------------------------------------------------------------------- Service org.bluez Interface org.bluez.HealthDevice Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods: dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Posible errors: org.bluez.Error.NotAllowed Boolean Echo() Sends an echo petition to the remote service. Returns True if response matches with the buffer sent. If some error is detected False value is returned. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.OutOfRange object CreateChannel(object application, string configuration) Creates a new data channel. The configuration should indicate the channel quality of service using one of this values "Reliable", "Streaming", "Any". Returns the object path that identifies the data channel that is already connected. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.HealthError void DestroyChannel(object channel) Destroys the data channel object. Only the creator of the channel or the creator of the HealthApplication that received the data channel will be able to destroy it. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotFound org.bluez.Error.NotAllowed Signals: void ChannelConnected(object channel) This signal is launched when a new data channel is created or when a known data channel is reconnected. void ChannelDeleted(object channel) This signal is launched when a data channel is deleted. After this signal the data channel path will not be valid and its path can be reused for future data channels. void PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. Properties: object MainChannel [readonly] The first reliable channel opened. It is needed by upper applications in order to send specific protocol data units. The first reliable can change after a reconnection. -------------------------------------------------------------------------------- Service org.bluez Interface org.bluez.HealthChannel Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/chanZZZ Only the process that created the data channel or the creator of the HealthApplication that received it will be able to call this methods. Methods: dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Possible errors: org.bluez.Error.NotAllowed fd Acquire() Returns the file descriptor for this data channel. If the data channel is not connected it will also reconnect. Possible errors: org.bluez.Error.NotConnected org.bluez.Error.NotAllowed void Release() Releases the fd. Application should also need to close() it. Possible errors: org.bluez.Error.NotAcquired org.bluez.Error.NotAllowed Properties: string Type [readonly] The quality of service of the data channel. ("Reliable" or "Streaming") object Device [readonly] Identifies the Remote Device that is connected with. Maps with a HealthDevice object. object Application [readonly] Identifies the HealthApplication to which this channel is related to (which indirectly defines its role and data type). bluez-4.101/doc/serial-api.txt0000644000000000000000000001054411766125764013106 00000000000000BlueZ D-Bus Serial API description ********************************** Copyright (C) 2004-2010 Marcel Holtmann Serial hierarchy ================ Service org.bluez Interface org.bluez.Serial Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods string Connect(string pattern) Connects to a specific RFCOMM based service on a remote device and then creates a RFCOMM TTY device for it. The RFCOMM TTY device is returned. Possible patterns: UUID 128 bit as string Profile short names, e.g: spp, dun RFCOMM channel as string, 1-30 Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.InProgress org.bluez.Error.ConnectionAttemptFailed org.bluez.Error.NotSupported Methods fd ConnectFD(string pattern) [experimental] Connects to a specific RFCOMM based service on a remote device and returns a file descriptor to talk with this device. Possible patterns: UUID 128 bit as string Profile short names, e.g: spp, dun RFCOMM channel as string, 1-30 Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.InProgress org.bluez.Error.ConnectionAttemptFailed org.bluez.Error.NotSupported void Disconnect(string device) Disconnect a RFCOMM TTY device that has been created by Connect method. To abort a connection attempt in case of errors or timeouts in the client it is fine to call this method. In that case one of patterns of the Connect method should be supplied instead of the TTY device. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.DoesNotExist Serial Proxy Manager hierarchy [experimental] ============================================= Service org.bluez Interface org.bluez.SerialProxyManager Object path [variable prefix]/{hci0,hci1,...} Methods array{string} ListProxies() Returns an array of the object path strings of all the proxies created for the adapter. string CreateProxy(string pattern, string address) Possible patterns: UUID 128 bit as string Profile short names, e.g: spp, dun RFCOMM channel as string, 1-30 Address is the path to the TTY or Unix socket to be used. Only one proxy per address (TTY or Unix socket) is allowed. The object path of created proxy is returned. On success this will emit a ProxyCreated signal. Possible Errors: org.bluez.Error.InvalidArguments org.bluez.Error.AlreadyExists org.bluez.Error.Failed void RemoveProxy(string path) This removes the proxy object at the given path. On success this will emit a ProxyRemoved signal. Possible Errors: org.bluez.Error.DoesNotExist org.bluez.Error.NotAuthorized Signals ProxyCreated(string path) This signal indicates a proxy was created. Parameter is object path of created proxy. ProxyRemoved(string path) This signal indicates a proxy was removed. Parameter is object path of removed proxy. Serial Proxy hierarchy [experimental] ===================================== Service org.bluez Interface org.bluez.SerialProxy Object path [variable prefix]/{hci0,hci1,...}/{proxy0,proxy1,...} Methods void Enable() Starts to listen to the TTY or Unix socket, allocates a RFCOMM channel and add record to the server. Possible errors: org.bluez.Error.Failed void Disable() Stops to listen to the TTY or Unix socket, shutdown the RFCOMM channel allocated for the proxy, and remove record from the server. Possible errors: org.bluez.Error.Failed dict GetInfo() Returns all properties for the proxy. See the properties section for available properties. void SetSerialParameters(string rate, uint8 data, uint8 stop, string parity) Configures serial communication setting baud rate, data bits, stop bits and parity. Doesn't allow change TTY settings if it is open. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotAuthorized Properties string uuid [readonly] 128-bit UUID that represents the available remote service. string address [readonly] Address is the path to the TTY or Unix socket name used, set when the proxy was created. uint8 channel [readonly] RFCOMM channel. boolean enabled [readonly] Indicates if the proxy is currently enabled. boolean connected [readonly] Indicates if the proxy is currently connected. bluez-4.101/doc/manager-api.txt0000644000000000000000000000375311376221745013236 00000000000000BlueZ D-Bus Manager API description *********************************** Copyright (C) 2004-2010 Marcel Holtmann Copyright (C) 2005-2006 Johan Hedberg Copyright (C) 2005-2006 Claudio Takahasi Copyright (C) 2006-2007 Luiz von Dentz Manager hierarchy ================= Service org.bluez Interface org.bluez.Manager Object path / Methods dict GetProperties() Returns all global properties. See the properties section for available properties. Possible Errors: org.bluez.Error.DoesNotExist org.bluez.Error.InvalidArguments object DefaultAdapter() Returns object path for the default adapter. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NoSuchAdapter object FindAdapter(string pattern) Returns object path for the specified adapter. Valid patterns are "hci0" or "00:11:22:33:44:55". Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NoSuchAdapter array{object} ListAdapters() {deprecated} Returns list of adapter object paths under /org/bluez. This method is deprecated, instead use the Adapters Property to get the list of adapter object paths. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.Failed org.bluez.Error.OutOfMemory Signals PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. AdapterAdded(object adapter) Parameter is object path of added adapter. AdapterRemoved(object adapter) Parameter is object path of removed adapter. DefaultAdapterChanged(object adapter) Parameter is object path of the new default adapter. In case all adapters are removed this signal will not be emitted. The AdapterRemoved signal has to be used to detect that no default adapter is selected or available anymore. Properties array{object} Adapters [readonly] List of adapter object paths. bluez-4.101/doc/audio-api.txt0000644000000000000000000002442711766125764012735 00000000000000BlueZ D-Bus Audio API description ********************************* Copyright (C) 2004-2010 Marcel Holtmann Copyright (C) 2005-2007 Johan Hedberg Copyright (C) 2005-2006 Brad Midgley Audio hierarchy =============== Service org.bluez Interface org.bluez.Audio Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX This is a generic audio interface that abstracts the different audio profiles. Methods void Connect() Connect all supported audio profiles on the device. void Disconnect() Disconnect all audio profiles on the device dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Signals void PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. Properties string State Possible values: "disconnected", "connecting", "connected" "disconnected" -> "connecting" Either an incoming or outgoing connection attempt ongoing. "connecting" -> "disconnected" Connection attempt failed "connecting" -> "connected" Successfully connected "connected" -> "disconnected" Disconnected from the remote device Headset hierarchy ================= Service org.bluez Interface org.bluez.Headset Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods void Connect() Connect to the HSP/HFP service on the remote device. void Disconnect() Disconnect from the HSP/HFP service on the remote device. boolean IsConnected() {deprecated} Returns TRUE if there is a active connection to the HSP/HFP connection on the remote device. void IndicateCall() Indicate an incoming call on the headset connected to the stream. Will continue to ring the headset about every 3 seconds. void CancelCall() Cancel the incoming call indication. void Play() {deprecated} Open the audio connection to the headset. void Stop() Close the audio connection. boolean IsPlaying() {deprecated} Returns true if an audio connection to the headset is active. uint16 GetSpeakerGain() {deprecated} Returns the current speaker gain if available, otherwise returns the error NotAvailable. uint16 GetMicrophoneGain() {deprecated} Returns the current microphone gain if available, otherwise returns the error NotAvailable. void SetSpeakerGain(uint16 gain) {deprecated} Changes the current speaker gain if possible. void SetMicrophoneGain(uint16 gain) {deprecated} Changes the current speaker gain if possible. dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Possible Errors: org.bluez.Error.InvalidArguments void SetProperty(string name, variant value) Changes the value of the specified property. Only properties that are listed a read-write are changeable. On success this will emit a PropertyChanged signal. Possible Errors: org.bluez.Error.DoesNotExist org.bluez.Error.InvalidArguments Signals void AnswerRequested() Sent when the answer button is pressed on the headset void Connected() {deprecated} Sent when the device has been connected to. void Disconnected() {deprecated} Sent when the device has been disconnected from. void Stopped() {deprecated} Sent when the audio connection is closed void Playing() {deprecated} Sent when the audio connection is opened void SpeakerGainChanged(uint16 gain) {deprecated} The speaker gain changed. void MicrophoneGainChanged(uint16 gain) {deprecated} The microphone gain changed. PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. properties string State [readonly] Possible values: "disconnected", "connecting", "connected", "playing" "disconnected" -> "connecting" Either an incoming or outgoing connection attempt ongoing. "connecting" -> "disconnected" Connection attempt failed "connecting" -> "connected" Successfully connected "connected" -> "playing" SCO audio connection successfully opened "playing" -> "connected" SCO audio connection closed "connected" -> "disconnected" "playing" -> "disconnected" Disconnected from the remote device boolean Connected [readonly] Indicates if there is a active connection to the HSP/HFP connection on the remote device. boolean Playing [readonly] Indicates if an audio connection to the headset is active. uint16 SpeakerGain [readwrite] The speaker gain when available. uint16 MicrophoneGain [readwrite] The speaker gain when available. AudioSink hierarchy =================== Service org.bluez Interface org.bluez.AudioSink Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods void Connect() Connect and setup a stream to a A2DP sink on the remote device. void Disconnect() Disconnect from the remote device. boolean IsConnected() {deprecated} Returns TRUE if a stream is setup to a A2DP sink on the remote device. dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Possible Errors: org.bluez.Error.InvalidArguments Signals void Connected() {deprecated} Sent when a successful connection has been made to the remote A2DP Sink void Disconnected() {deprecated} Sent when the device has been disconnected from. void Playing() {deprecated} Sent when a stream with remote device is started. void Stopped() {deprecated} Sent when a stream with remote device is suspended. PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. properties string State [readonly] Possible values: "disconnected", "connecting", "connected", "playing" "disconnected" -> "connecting" Either an incoming or outgoing connection attempt ongoing. "connecting" -> "disconnected" Connection attempt failed "connecting" -> "connected" Successfully connected "connected" -> "playing" Audio stream active "playing" -> "connected" Audio stream suspended "connected" -> "disconnected" "playing" -> "disconnected" Disconnected from the remote device boolean Connected [readonly] Indicates if a stream is setup to a A2DP sink on the remote device. boolean Playing [readonly] Indicates if a stream is active to a A2DP sink on the remote device. AudioSource hierarchy ===================== Service org.bluez Interface org.bluez.AudioSource Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods void Connect() Connect and setup a stream to a A2DP source on the remote device. void Disconnect() Disconnect from the remote device. dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Possible Errors: org.bluez.Error.InvalidArguments Signals PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. properties string State [readonly] Possible values: "disconnected", "connecting", "connected", "playing" "disconnected" -> "connecting" Either an incoming or outgoing connection attempt ongoing. "connecting" -> "disconnected" Connection attempt failed "connecting" -> "connected" Successfully connected "connected" -> "playing" Audio stream active "playing" -> "connected" Audio stream suspended "connected" -> "disconnected" "playing" -> "disconnected" Disconnected from the remote device HeadsetGateway hierarchy ======================== Service org.bluez Interface org.bluez.HeadsetGateway Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX This interface is available for remote devices which can function in the Audio Gateway role of the HFP profiles. Methods void Connect() Connect to the AG service on the remote device. void Disconnect() Disconnect from the AG service on the remote device void AnswerCall() It has to called only after Ring signal received. void TerminateCall() Terminate call which is running or reject an incoming call. This has nothing with any 3-way situation incl. RaH. Just plain old PDH. void Call(string number) Dial a number 'number'. No number processing is done thus if AG would reject to dial it don't blame me :) string GetOperatorName() Find out the name of the currently selected network operator by AG. void SendDTMF(string digits) Will send each digit in the 'digits' sequentially. Would send nothing if there is non-dtmf digit. string GetSubscriberNumber() Get the voicecall subscriber number of AG dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Signals void Ring(string number) Someone's calling from 'number'. Caller number is provided as received from AG. void CallTerminated() Call failed to set up. It means that we tried to call someone or someone tried to call us but call was not accepted. void CallStarted() Call set up successfully. void CallEnded() Call was started and now ended. In contrast with CallTerminated where call didn't started PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. properties boolean Connected [readonly] Indicates if there is an active connection to the AG service on the remote device. uint16 RegistrationStatus [readonly] Service availability indicator of AG, where: 0 implies no service. No Home/Roam network available. 1 implies presence of service. Home/Roam network available. uint16 SignalStrength [readonly] Signal strength indicator of AG, the value ranges from 0 to 5. uint16 RoamingStatus [readonly] Roaming status indicator of AG, where: 0 means roaming is not active 1 means a roaming is active uint16 BatteryCharge [readonly] Battery Charge indicator of AG, the value ranges from 0 to 5. uint16 SpeakerGain [readonly] The speaker gain when available. uint16 MicrophoneGain [readonly] The speaker gain when available. bluez-4.101/doc/attribute-api.txt0000644000000000000000000001132311766125764013626 00000000000000BlueZ D-Bus Attribute API description ************************************* Copyright (C) 2004-2010 Marcel Holtmann Service details --------------- One service object path for every remote SDP record or service in the attribute database. One service object path for every local SDP record or service from attribute database. Local services are children of the adapter object path. Remote services are children of the remote device object path. This doesn't solve the problem where local attributes can have different instances based on the remote device. In general the idea is to also represent SDP records as services so that new style application can just use the service interfaces to retrieve the needed information. That way the usage of SDP and GATT would be mostly fully transparent and a differentiation becomes unimportant in the future. A service consists of some generic service information and a set of characteristics. All characteristic are presented as object path as well. Local Service hierarchy ======================= Service org.bluez Interface org.bluez.Service org.bluez.Characteristic Object path [prefix]/{hci0}/{service0, service1, ...} Methods Properties Device Service hierarchy ======================== Service org.bluez Interface org.bluez.Characteristic Object path [prefix]/{hci0}/{device0}/{service0, service1, ...} [prefix]/{hci0}/{device1}/{service0, service1, ...} Methods dict GetProperties() Returns all properties for the interface. See the Properties section for the available properties. array{object} DiscoverCharacteristics() Discover all characteristics that belongs in this service. When it returns all the characteristics paths will be already registered. It will return the characteristics paths as soon as they are discovered. After that it will try to read all values. RegisterCharacteristicsWatcher(object agent) Register a watcher to monitor characteristic changes. A watcher will be registered for this service and will notify about any changed characteristics in the service. This also notifies about any included characteristics. UnregisterCharacteristicsWatcher(object agent) Unregister a watcher. Properties string Name (mandatory) [readonly] General name of service string Description (optional) [readonly] Description of service string UUID (mandatory) [readonly] UUID of service. Service class value for SDP and GATT UUID for attribute based services. array{object} Characteristics [readonly] This list contains the characteristics owned by this specific service and other characteristics from service includes. That way no complicated service includes array is needed. Device Characteristic hierarchy =============================== Service org.bluez Interface org.bluez.Characteristic Object path [prefix]/{hci0}/{device0}/{service0}/{characteristic0,...} [prefix]/{hci0}/{device0}/{service1}/{characteristic0,...} Methods dict GetProperties() Returns all properties for the characteristic. See the properties section for available properties. void SetProperty(string name, variant value) Changes the value of the specified property. Only read-write properties can be changed. On success this will emit a PropertyChanged signal. Possible Errors: org.bluez.Error.InvalidArguments Properties string UUID [readonly] UUID128 of this characteristic. string Name [readonly] Optional field containing a friendly name for the Characteristic UUID. string Description [readonly] Textual optional characteristic descriptor describing the Characteristic Value. struct Format [readonly] Optional Characteristic descriptor which defines the format of the Characteristic Value. For numeric values, the actual value can be value * 10^Exponent. NameSpace and Description are defined on the Assigned Number Specification. uint8 | Format: format of the value uint8 | Exponent: Field to determine how the value is | further formatted. uint16 | Unit: unit of the characteristic uint8 | NameSpace: Name space of description. uint16 | Description: Description of the characteristic defined | in a high layer profile. array{byte} Value [readwrite] Raw value of the Characteristic Value attribute. string Representation (of the binary Value) [readonly] Friendly representation of the Characteristic Value based on the format attribute. Characteristic Watcher hierarchy =============================== Service unique name Interface org.bluez.Watcher Object path freely definable Methods void ValueChanged(object characteristic, array{byte}) New raw value of the Characteristic Value attribute. bluez-4.101/doc/hfp-api.txt0000644000000000000000000000450311766125764012402 00000000000000Gateway hierarchy ======================== Service org.bluez Interface org.bluez.HandsfreeGateway Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX This interface is available for remote devices which can function in the Audio Gateway role of the HFP profiles. It is intended to be used with external telephony stacks / handlers of the HFP protocol. Methods void Connect() Connect to the AG service on the remote device. void Disconnect() Disconnect from the AG service on the remote device dict GetProperties() Returns all properties for the interface. See the properties section for available properties. void RegisterAgent(object path) The object path defines the path the of the agent that will be called when a new Handsfree connection is established. If an application disconnects from the bus all of its registered agents will be removed. void UnregisterAgent(object path) This unregisters the agent that has been previously registered. The object path parameter must match the same value that has been used on registration. Possible Errors: org.bluez.Error.Failed org.bluez.Error.InvalidArguments Signals PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. Properties string State [readonly] Indicates the state of the connection. Possible values are: "disconnected" "connecting" "connected" "playing" HandsfreeAgent hierarchy =============== Service unique name Interface org.bluez.HandsfreeAgent Object path freely definable Methods void NewConnection(filedescriptor fd, uint16 version) This method gets called whenever a new handsfree connection has been established. The objectpath contains the object path of the remote device. The agent should only return successfully once the establishment of the service level connection (SLC) has been completed. In the case of Handsfree this means that BRSF exchange has been performed and necessary initialization has been done. Possible Errors: org.bluez.Error.InvalidArguments org.bluez.Error.Failed void Release() This method gets called whenever the service daemon unregisters the agent or whenever the Adapter where the HandsfreeAgent registers itself is removed. bluez-4.101/doc/device-api.txt0000644000000000000000000001342211766125764013064 00000000000000BlueZ D-Bus Device API description ********************************** Copyright (C) 2004-2010 Marcel Holtmann Copyright (C) 2005-2006 Johan Hedberg Copyright (C) 2005-2006 Claudio Takahasi Copyright (C) 2006-2007 Luiz von Dentz Device hierarchy ================ Service org.bluez Interface org.bluez.Device Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods dict GetProperties() Returns all properties for the device. See the properties section for available properties. Possible Errors: org.bluez.Error.DoesNotExist org.bluez.Error.InvalidArguments void SetProperty(string name, variant value) Changes the value of the specified property. Only properties that are listed a read-write are changeable. On success this will emit a PropertyChanged signal. Possible Errors: org.bluez.Error.DoesNotExist org.bluez.Error.InvalidArguments dict DiscoverServices(string pattern) This method starts the service discovery to retrieve remote service records. The pattern parameter can be used to specify specific UUIDs. And empty string will look for the public browse group. The return value is a dictionary with the record handles as keys and the service record in XML format as values. The key is uint32 and the value a string for this dictionary. Possible errors: org.bluez.Error.NotReady org.bluez.Error.Failed org.bluez.Error.InProgress void CancelDiscovery() This method will cancel any previous DiscoverServices transaction. Possible errors: org.bluez.Error.NotReady org.bluez.Error.Failed org.bluez.Error.NotAuthorized void Disconnect() This method disconnects a specific remote device by terminating the low-level ACL connection. The use of this method should be restricted to administrator use. A DisconnectRequested signal will be sent and the actual disconnection will only happen 2 seconds later. This enables upper-level applications to terminate their connections gracefully before the ACL connection is terminated. Possible errors: org.bluez.Error.NotConnected array{object} ListNodes() Returns list of device node object paths. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.Failed org.bluez.Error.OutOfMemory object CreateNode(string uuid) Creates a persistent device node binding with a remote device. The actual support for the specified UUID depends if the device driver has support for persistent binding. At the moment only RFCOMM TTY nodes are supported. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotSupported void RemoveNode(object node) Removes a persistent device node binding. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.DoesNotExist Signals PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. DisconnectRequested() This signal will be sent when a low level disconnection to a remote device has been requested. The actual disconnection will happen 2 seconds later. NodeCreated(object node) Parameter is object path of created device node. NodeRemoved(object node) Parameter is object path of removed device node. Properties string Address [readonly] The Bluetooth device address of the remote device. string Name [readonly] The Bluetooth remote name. This value can not be changed. Use the Alias property instead. uint16 Vendor [readonly] Vendor unique numeric identifier. uint16 VendorSource [readonly] Vendor source numeric identifier. uint16 Product [readonly] Product unique numeric identifier. uint16 Version [readonly] Version unique numeric identifier. string Icon [readonly] Proposed icon name according to the freedesktop.org icon naming specification. uint32 Class [readonly] The Bluetooth class of device of the remote device. array{string} UUIDs [readonly] List of 128-bit UUIDs that represents the available remote services. array{object} Services [readonly] List of characteristics based services. boolean Paired [readonly] Indicates if the remote device is paired. boolean Connected [readonly] Indicates if the remote device is currently connected. A PropertyChanged signal indicate changes to this status. boolean Trusted [readwrite] Indicates if the remote is seen as trusted. This setting can be changed by the application. boolean Blocked [readwrite] If set to true any incoming connections from the device will be immediately rejected. Any device drivers will also be removed and no new ones will be probed as long as the device is blocked. string Alias [readwrite] The name alias for the remote device. The alias can be used to have a different friendly name for the remote device. In case no alias is set, it will return the remote device name. Setting an empty string as alias will convert it back to the remote device name. When resetting the alias with an empty string, the emitted PropertyChanged signal will show the remote name again. array{object} Nodes [readonly] List of device node object paths. object Adapter [readonly] The object path of the adapter the device belongs to. boolean LegacyPairing [readonly] Set to true if the device only supports the pre-2.1 pairing mechanism. This property is useful in the Adapter.DeviceFound signal to anticipate whether legacy or simple pairing will occur. Note that this property can exhibit false-positives in the case of Bluetooth 2.1 (or newer) devices that have disabled Extended Inquiry Response support. bluez-4.101/doc/service-api.txt0000644000000000000000000000344011376221745013255 00000000000000BlueZ D-Bus Adapter API description *********************************** Copyright (C) 2004-2010 Marcel Holtmann Copyright (C) 2005-2006 Johan Hedberg Copyright (C) 2005-2006 Claudio Takahasi Copyright (C) 2006-2007 Luiz von Dentz Service hierarchy ================= Service org.bluez Interface org.bluez.Service Object path [variable prefix]/{hci0,hci1,...} Methods uint32 AddRecord(string record) Adds a new service record from the XML description and returns the assigned record handle. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.Failed void UpdateRecord(uint32 handle, string record) Updates a given service record provided in the XML format. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotAvailable org.bluez.Error.Failed void RemoveRecord(uint32 handle) Remove a service record identified by its handle. It is only possible to remove service records that where added by the current connection. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotAuthorized org.bluez.Error.DoesNotExist org.bluez.Error.Failed void RequestAuthorization(string address, uint32 handle) Request an authorization for an incoming connection for a specific service record. The service record needs to be registered via AddRecord first. Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotAuthorized org.bluez.Error.DoesNotExist org.bluez.Error.Failed void CancelAuthorization() Possible errors: org.bluez.Error.InvalidArguments org.bluez.Error.NotAuthorized org.bluez.Error.DoesNotExist org.bluez.Error.Failed bluez-4.101/doc/network-api.txt0000644000000000000000000000435011571052274013303 00000000000000BlueZ D-Bus Network API description *********************************** Copyright (C) 2004-2010 Marcel Holtmann Network hierarchy ================= Service org.bluez Interface org.bluez.Network Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods string Connect(string uuid) Connect to the network device and return the network interface name. Examples of the interface name are bnep0, bnep1 etc. uuid can be either one of "gn", "panu" or "nap" (case insensitive) or a traditional string representation of UUID or a hexadecimal number. The connection will be closed and network device released either upon calling Disconnect() or when the client disappears from the message bus. Possible errors: org.bluez.Error.AlreadyConnected org.bluez.Error.ConnectionAttemptFailed void Disconnect() Disconnect from the network device. To abort a connection attempt in case of errors or timeouts in the client it is fine to call this method. Possible errors: org.bluez.Error.Failed dict GetProperties() Returns all properties for the interface. See the properties section for available properties. Signals PropertyChanged(string name, variant value) This signal indicates a changed value of the given property. Properties boolean Connected [readonly] Indicates if the device is connected. string Interface [readonly] Indicates the network interface name when available. string UUID [readonly] Indicates the connection role when available. Network server hierarchy ======================== Service org.bluez Interface org.bluez.NetworkServer Object path /org/bluez/{hci0,hci1,...} Methods void Register(string uuid, string bridge) Register server for the provided UUID. Every new connection to this server will be added the bridge interface. Valid UUIDs are "gn", "panu" or "nap". Initially no network server SDP is provided. Only after this method a SDP record will be available and the BNEP server will be ready for incoming connections. void Unregister(string uuid) Unregister the server for provided UUID. All servers will be automatically unregistered when the calling application terminates. bluez-4.101/doc/assigned-numbers.txt0000644000000000000000000000060611571052274014311 00000000000000RFCOMM Channels =============== Since there are a limited amount of possible RFCOMM channels (1-31) they've been pre-allocated for currently known profiles in order to avoid conflicts. Profile Channel ----------------------- DUN 1 HFP HF 7 OPP 9 FTP 10 BIP 11 HSP AG 12 HFP AG 13 SYNCH (IrMC) 14 PBAP 15 MAP 16 SyncEvolution 19 PC/Ovi Suite 24 SyncML Client 25 SyncML Server 26 bluez-4.101/doc/control-api.txt0000644000000000000000000000171411766125764013306 00000000000000BlueZ D-Bus Control API description *********************************** Copyright (C) 2004-2010 Marcel Holtmann Copyright (C) 2007-2008 David Stockwell Control hierarchy ================= Service org.bluez Interface org.bluez.Control Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX Methods boolean IsConnected() {deprecated} Returns True if connected, otherwise FALSE. dict GetProperties() Returns all properties for the interface. See the properties section for available properties. void VolumeUp() Adjust remote volume one step up void VolumeDown() Adjust remote volume one step down Signals Connected() {deprecated} Sent when a successful AVRCP connection has been made to the remote device. Disconnected() {deprecated} Sent when the AVRCP connection to the remote device has been disconnected. Properties boolean Connected [readonly] bluez-4.101/doc/agent-api.txt0000644000000000000000000000741511766125764012730 00000000000000BlueZ D-Bus Agent API description ********************************** Copyright (C) 2004-2010 Marcel Holtmann Copyright (C) 2005-2006 Johan Hedberg Agent hierarchy =============== Service unique name Interface org.bluez.Agent Object path freely definable Methods void Release() This method gets called when the service daemon unregisters the agent. An agent can use it to do cleanup tasks. There is no need to unregister the agent, because when this method gets called it has already been unregistered. string RequestPinCode(object device) This method gets called when the service daemon needs to get the passkey for an authentication. The return value should be a string of 1-16 characters length. The string can be alphanumeric. Possible errors: org.bluez.Error.Rejected org.bluez.Error.Canceled uint32 RequestPasskey(object device) This method gets called when the service daemon needs to get the passkey for an authentication. The return value should be a numeric value between 0-999999. Possible errors: org.bluez.Error.Rejected org.bluez.Error.Canceled void DisplayPasskey(object device, uint32 passkey, uint8 entered) This method gets called when the service daemon needs to display a passkey for an authentication. The entered parameter indicates the number of already typed keys on the remote side. An empty reply should be returned. When the passkey needs no longer to be displayed, the Cancel method of the agent will be called. During the pairing process this method might be called multiple times to update the entered value. Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if the value contains less than 6 digits. void DisplayPinCode(object device, string pincode) This method gets called when the service daemon needs to display a pincode for an authentication. An empty reply should be returned. When the pincode needs no longer to be displayed, the Cancel method of the agent will be called. If this method is not implemented the RequestPinCode method will be used instead. This is used during the pairing process of keyboards that don't support Bluetooth 2.1 Secure Simple Pairing, in contrast to DisplayPasskey which is used for those that do. This method will only ever be called once since older keyboards do not support typing notification. Note that the PIN will always be a 6-digit number, zero-padded to 6 digits. This is for harmony with the later specification. void RequestConfirmation(object device, uint32 passkey) This method gets called when the service daemon needs to confirm a passkey for an authentication. To confirm the value it should return an empty reply or an error in case the passkey is invalid. Note that the passkey will always be a 6-digit number, so the display should be zero-padded at the start if the value contains less than 6 digits. Possible errors: org.bluez.Error.Rejected org.bluez.Error.Canceled void Authorize(object device, string uuid) This method gets called when the service daemon needs to authorize a connection/service request. Possible errors: org.bluez.Error.Rejected org.bluez.Error.Canceled void ConfirmModeChange(string mode) This method gets called if a mode change is requested that needs to be confirmed by the user. An example would be leaving flight mode. Possible errors: org.bluez.Error.Rejected org.bluez.Error.Canceled void Cancel() This method gets called to indicate that the agent request failed before a reply was returned. bluez-4.101/src/0000755000000000000000000000000011771120005010370 500000000000000bluez-4.101/src/sdp-client.c0000644000000000000000000001754611766125764012560 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "btio.h" #include "sdp-client.h" /* Number of seconds to keep a sdp_session_t in the cache */ #define CACHE_TIMEOUT 2 struct cached_sdp_session { bdaddr_t src; bdaddr_t dst; sdp_session_t *session; guint timer; }; static GSList *cached_sdp_sessions = NULL; static gboolean cached_session_expired(gpointer user_data) { struct cached_sdp_session *cached = user_data; cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, cached); sdp_close(cached->session); g_free(cached); return FALSE; } static sdp_session_t *get_cached_sdp_session(const bdaddr_t *src, const bdaddr_t *dst) { GSList *l; for (l = cached_sdp_sessions; l != NULL; l = l->next) { struct cached_sdp_session *c = l->data; sdp_session_t *session; if (bacmp(&c->src, src) || bacmp(&c->dst, dst)) continue; g_source_remove(c->timer); session = c->session; cached_sdp_sessions = g_slist_remove(cached_sdp_sessions, c); g_free(c); return session; } return NULL; } static sdp_session_t *get_sdp_session(const bdaddr_t *src, const bdaddr_t *dst) { sdp_session_t *session; session = get_cached_sdp_session(src, dst); if (session) return session; return sdp_connect(src, dst, SDP_NON_BLOCKING); } static void cache_sdp_session(bdaddr_t *src, bdaddr_t *dst, sdp_session_t *session) { struct cached_sdp_session *cached; cached = g_new0(struct cached_sdp_session, 1); bacpy(&cached->src, src); bacpy(&cached->dst, dst); cached->session = session; cached_sdp_sessions = g_slist_append(cached_sdp_sessions, cached); cached->timer = g_timeout_add_seconds(CACHE_TIMEOUT, cached_session_expired, cached); } struct search_context { bdaddr_t src; bdaddr_t dst; sdp_session_t *session; bt_callback_t cb; bt_destroy_t destroy; gpointer user_data; uuid_t uuid; guint io_id; }; static GSList *context_list = NULL; static void search_context_cleanup(struct search_context *ctxt) { context_list = g_slist_remove(context_list, ctxt); if (ctxt->destroy) ctxt->destroy(ctxt->user_data); g_free(ctxt); } static void search_completed_cb(uint8_t type, uint16_t status, uint8_t *rsp, size_t size, void *user_data) { struct search_context *ctxt = user_data; sdp_list_t *recs = NULL; int scanned, seqlen = 0, bytesleft = size; uint8_t dataType; int err = 0; if (status || type != SDP_SVC_SEARCH_ATTR_RSP) { err = -EPROTO; goto done; } scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen); if (!scanned || !seqlen) goto done; rsp += scanned; bytesleft -= scanned; do { sdp_record_t *rec; int recsize; recsize = 0; rec = sdp_extract_pdu(rsp, bytesleft, &recsize); if (!rec) break; if (!recsize) { sdp_record_free(rec); break; } scanned += recsize; rsp += recsize; bytesleft -= recsize; recs = sdp_list_append(recs, rec); } while (scanned < (ssize_t) size && bytesleft > 0); done: cache_sdp_session(&ctxt->src, &ctxt->dst, ctxt->session); if (ctxt->cb) ctxt->cb(recs, err, ctxt->user_data); if (recs) sdp_list_free(recs, (sdp_free_func_t) sdp_record_free); search_context_cleanup(ctxt); } static gboolean search_process_cb(GIOChannel *chan, GIOCondition cond, gpointer user_data) { struct search_context *ctxt = user_data; int err = 0; if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL)) { err = EIO; goto failed; } if (sdp_process(ctxt->session) < 0) goto failed; return TRUE; failed: if (err) { sdp_close(ctxt->session); ctxt->session = NULL; if (ctxt->cb) ctxt->cb(NULL, err, ctxt->user_data); search_context_cleanup(ctxt); } return FALSE; } static gboolean connect_watch(GIOChannel *chan, GIOCondition cond, gpointer user_data) { struct search_context *ctxt = user_data; sdp_list_t *search, *attrids; uint32_t range = 0x0000ffff; socklen_t len; int sk, err, sk_err = 0; sk = g_io_channel_unix_get_fd(chan); ctxt->io_id = 0; len = sizeof(sk_err); if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0) err = -errno; else err = -sk_err; if (err != 0) goto failed; if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) { err = -EIO; goto failed; } search = sdp_list_append(NULL, &ctxt->uuid); attrids = sdp_list_append(NULL, &range); if (sdp_service_search_attr_async(ctxt->session, search, SDP_ATTR_REQ_RANGE, attrids) < 0) { sdp_list_free(attrids, NULL); sdp_list_free(search, NULL); err = -EIO; goto failed; } sdp_list_free(attrids, NULL); sdp_list_free(search, NULL); /* Set callback responsible for update the internal SDP transaction */ ctxt->io_id = g_io_add_watch(chan, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, search_process_cb, ctxt); return FALSE; failed: sdp_close(ctxt->session); ctxt->session = NULL; if (ctxt->cb) ctxt->cb(NULL, err, ctxt->user_data); search_context_cleanup(ctxt); return FALSE; } static int create_search_context(struct search_context **ctxt, const bdaddr_t *src, const bdaddr_t *dst, uuid_t *uuid) { sdp_session_t *s; GIOChannel *chan; if (!ctxt) return -EINVAL; s = get_sdp_session(src, dst); if (!s) return -errno; *ctxt = g_try_malloc0(sizeof(struct search_context)); if (!*ctxt) { sdp_close(s); return -ENOMEM; } bacpy(&(*ctxt)->src, src); bacpy(&(*ctxt)->dst, dst); (*ctxt)->session = s; (*ctxt)->uuid = *uuid; chan = g_io_channel_unix_new(sdp_get_socket(s)); (*ctxt)->io_id = g_io_add_watch(chan, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL, connect_watch, *ctxt); g_io_channel_unref(chan); return 0; } int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst, uuid_t *uuid, bt_callback_t cb, void *user_data, bt_destroy_t destroy) { struct search_context *ctxt = NULL; int err; if (!cb) return -EINVAL; err = create_search_context(&ctxt, src, dst, uuid); if (err < 0) return err; ctxt->cb = cb; ctxt->destroy = destroy; ctxt->user_data = user_data; context_list = g_slist_append(context_list, ctxt); return 0; } static gint find_by_bdaddr(gconstpointer data, gconstpointer user_data) { const struct search_context *ctxt = data, *search = user_data; int ret; ret = bacmp(&ctxt->src, &search->src); if (ret != 0) return ret; return bacmp(&ctxt->dst, &search->dst); } int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst) { struct search_context match, *ctxt; GSList *l; memset(&match, 0, sizeof(match)); bacpy(&match.src, src); bacpy(&match.dst, dst); /* Ongoing SDP Discovery */ l = g_slist_find_custom(context_list, &match, find_by_bdaddr); if (l == NULL) return -ENOENT; ctxt = l->data; if (!ctxt->session) return -ENOTCONN; if (ctxt->io_id) g_source_remove(ctxt->io_id); if (ctxt->session) sdp_close(ctxt->session); search_context_cleanup(ctxt); return 0; } void bt_clear_cached_session(const bdaddr_t *src, const bdaddr_t *dst) { sdp_session_t *session; session = get_cached_sdp_session(src, dst); if (session) sdp_close(session); } bluez-4.101/src/sdpd-database.c0000644000000000000000000001561211571052274013167 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2001-2002 Nokia Corporation * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * Copyright (C) 2002-2003 Stephen Crane * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "sdpd.h" #include "log.h" #include "adapter.h" #include "manager.h" static sdp_list_t *service_db; static sdp_list_t *access_db; typedef struct { uint32_t handle; bdaddr_t device; } sdp_access_t; /* * Ordering function called when inserting a service record. * The service repository is a linked list in sorted order * and the service record handle is the sort key */ int record_sort(const void *r1, const void *r2) { const sdp_record_t *rec1 = r1; const sdp_record_t *rec2 = r2; if (!rec1 || !rec2) { error("NULL RECORD LIST FATAL"); return -1; } return rec1->handle - rec2->handle; } static int access_sort(const void *r1, const void *r2) { const sdp_access_t *rec1 = r1; const sdp_access_t *rec2 = r2; if (!rec1 || !rec2) { error("NULL RECORD LIST FATAL"); return -1; } return rec1->handle - rec2->handle; } static void access_free(void *p) { free(p); } /* * Reset the service repository by deleting its contents */ void sdp_svcdb_reset(void) { sdp_list_free(service_db, (sdp_free_func_t) sdp_record_free); sdp_list_free(access_db, access_free); } typedef struct _indexed { int sock; sdp_record_t *record; } sdp_indexed_t; static sdp_list_t *socket_index; /* * collect all services registered over this socket */ void sdp_svcdb_collect_all(int sock) { sdp_list_t *p, *q; for (p = socket_index, q = 0; p; ) { sdp_indexed_t *item = p->data; if (item->sock == sock) { sdp_list_t *next = p->next; sdp_record_remove(item->record->handle); sdp_record_free(item->record); free(item); if (q) q->next = next; else socket_index = next; free(p); p = next; } else if (item->sock > sock) return; else { q = p; p = p->next; } } } void sdp_svcdb_collect(sdp_record_t *rec) { sdp_list_t *p, *q; for (p = socket_index, q = 0; p; q = p, p = p->next) { sdp_indexed_t *item = p->data; if (rec == item->record) { free(item); if (q) q->next = p->next; else socket_index = p->next; free(p); return; } } } static int compare_indices(const void *i1, const void *i2) { const sdp_indexed_t *s1 = i1; const sdp_indexed_t *s2 = i2; return s1->sock - s2->sock; } void sdp_svcdb_set_collectable(sdp_record_t *record, int sock) { sdp_indexed_t *item = malloc(sizeof(sdp_indexed_t)); item->sock = sock; item->record = record; socket_index = sdp_list_insert_sorted(socket_index, item, compare_indices); } /* * Add a service record to the repository */ void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec) { struct btd_adapter *adapter; sdp_access_t *dev; SDPDBG("Adding rec : 0x%lx", (long) rec); SDPDBG("with handle : 0x%x", rec->handle); service_db = sdp_list_insert_sorted(service_db, rec, record_sort); dev = malloc(sizeof(*dev)); if (!dev) return; bacpy(&dev->device, device); dev->handle = rec->handle; access_db = sdp_list_insert_sorted(access_db, dev, access_sort); if (bacmp(device, BDADDR_ANY) == 0) { manager_foreach_adapter(adapter_service_insert, rec); return; } adapter = manager_find_adapter(device); if (adapter) adapter_service_insert(adapter, rec); } static sdp_list_t *record_locate(uint32_t handle) { if (service_db) { sdp_list_t *p; sdp_record_t r; r.handle = handle; p = sdp_list_find(service_db, &r, record_sort); return p; } SDPDBG("Could not find svcRec for : 0x%x", handle); return NULL; } static sdp_list_t *access_locate(uint32_t handle) { if (access_db) { sdp_list_t *p; sdp_access_t a; a.handle = handle; p = sdp_list_find(access_db, &a, access_sort); return p; } SDPDBG("Could not find access data for : 0x%x", handle); return NULL; } /* * Given a service record handle, find the record associated with it. */ sdp_record_t *sdp_record_find(uint32_t handle) { sdp_list_t *p = record_locate(handle); if (!p) { SDPDBG("Couldn't find record for : 0x%x", handle); return 0; } return p->data; } /* * Given a service record handle, remove its record from the repository */ int sdp_record_remove(uint32_t handle) { sdp_list_t *p = record_locate(handle); sdp_record_t *r; sdp_access_t *a; if (!p) { error("Remove : Couldn't find record for : 0x%x", handle); return -1; } r = p->data; if (r) service_db = sdp_list_remove(service_db, r); p = access_locate(handle); if (p == NULL || p->data == NULL) return 0; a = p->data; if (bacmp(&a->device, BDADDR_ANY) != 0) { struct btd_adapter *adapter = manager_find_adapter(&a->device); if (adapter) adapter_service_remove(adapter, r); } else manager_foreach_adapter(adapter_service_remove, r); access_db = sdp_list_remove(access_db, a); access_free(a); return 0; } /* * Return a pointer to the linked list containing the records in sorted order */ sdp_list_t *sdp_get_record_list(void) { return service_db; } sdp_list_t *sdp_get_access_list(void) { return access_db; } int sdp_check_access(uint32_t handle, bdaddr_t *device) { sdp_list_t *p = access_locate(handle); sdp_access_t *a; if (!p) return 1; a = p->data; if (!a) return 1; if (bacmp(&a->device, device) && bacmp(&a->device, BDADDR_ANY) && bacmp(device, BDADDR_ANY)) return 0; return 1; } uint32_t sdp_next_handle(void) { uint32_t handle = 0x10000; while (sdp_record_find(handle)) handle++; return handle; } void sdp_init_services_list(bdaddr_t *device) { sdp_list_t *p; DBG(""); for (p = access_db; p != NULL; p = p->next) { sdp_access_t *access = p->data; sdp_record_t *rec; if (bacmp(BDADDR_ANY, &access->device)) continue; rec = sdp_record_find(access->handle); if (rec == NULL) continue; SDPDBG("adding record with handle %x", access->handle); manager_foreach_adapter(adapter_service_insert, rec); } } bluez-4.101/src/attrib-server.c0000644000000000000000000010564011766125764013300 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "log.h" #include "gdbus.h" #include "btio.h" #include "sdpd.h" #include "hcid.h" #include "adapter.h" #include "device.h" #include "manager.h" #include "gattrib.h" #include "att.h" #include "gatt.h" #include "att-database.h" #include "storage.h" #include "attrib-server.h" static GSList *servers = NULL; struct gatt_server { struct btd_adapter *adapter; GIOChannel *l2cap_io; GIOChannel *le_io; uint32_t gatt_sdp_handle; uint32_t gap_sdp_handle; GList *database; GSList *clients; uint16_t name_handle; uint16_t appearance_handle; }; struct gatt_channel { bdaddr_t src; bdaddr_t dst; GAttrib *attrib; guint mtu; gboolean le; guint id; gboolean encrypted; struct gatt_server *server; guint cleanup_id; struct btd_device *device; }; struct group_elem { uint16_t handle; uint16_t end; uint8_t *data; uint16_t len; }; static bt_uuid_t prim_uuid = { .type = BT_UUID16, .value.u16 = GATT_PRIM_SVC_UUID }; static bt_uuid_t snd_uuid = { .type = BT_UUID16, .value.u16 = GATT_SND_SVC_UUID }; static bt_uuid_t ccc_uuid = { .type = BT_UUID16, .value.u16 = GATT_CLIENT_CHARAC_CFG_UUID }; static void attrib_free(void *data) { struct attribute *a = data; g_free(a->data); g_free(a); } static void channel_free(struct gatt_channel *channel) { if (channel->cleanup_id) g_source_remove(channel->cleanup_id); if (channel->device) btd_device_unref(channel->device); g_attrib_unref(channel->attrib); g_free(channel); } static void gatt_server_free(struct gatt_server *server) { g_list_free_full(server->database, attrib_free); if (server->l2cap_io != NULL) { g_io_channel_unref(server->l2cap_io); g_io_channel_shutdown(server->l2cap_io, FALSE, NULL); } if (server->le_io != NULL) { g_io_channel_unref(server->le_io); g_io_channel_shutdown(server->le_io, FALSE, NULL); } g_slist_free_full(server->clients, (GDestroyNotify) channel_free); if (server->gatt_sdp_handle > 0) remove_record_from_server(server->gatt_sdp_handle); if (server->gap_sdp_handle > 0) remove_record_from_server(server->gap_sdp_handle); if (server->adapter != NULL) btd_adapter_unref(server->adapter); g_free(server); } static gint adapter_cmp_addr(gconstpointer a, gconstpointer b) { const struct gatt_server *server = a; const bdaddr_t *bdaddr = b; bdaddr_t src; adapter_get_address(server->adapter, &src); return bacmp(&src, bdaddr); } static gint adapter_cmp(gconstpointer a, gconstpointer b) { const struct gatt_server *server = a; const struct btd_adapter *adapter = b; if (server->adapter == adapter) return 0; return -1; } static struct gatt_server *find_gatt_server(const bdaddr_t *bdaddr) { GSList *l; l = g_slist_find_custom(servers, bdaddr, adapter_cmp_addr); if (l == NULL) { char addr[18]; ba2str(bdaddr, addr); error("No GATT server found in %s", addr); return NULL; } return l->data; } static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t end) { sdp_list_t *svclass_id, *apseq, *proto[2], *root, *aproto; uuid_t root_uuid, proto_uuid, l2cap; sdp_record_t *record; sdp_data_t *psm, *sh, *eh; uint16_t lp = ATT_PSM; if (uuid == NULL) return NULL; if (start > end) return NULL; record = sdp_record_alloc(); if (record == NULL) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_list_free(root, NULL); svclass_id = sdp_list_append(NULL, uuid); sdp_set_service_classes(record, svclass_id); sdp_list_free(svclass_id, NULL); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); psm = sdp_data_alloc(SDP_UINT16, &lp); proto[0] = sdp_list_append(proto[0], psm); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&proto_uuid, ATT_UUID); proto[1] = sdp_list_append(NULL, &proto_uuid); sh = sdp_data_alloc(SDP_UINT16, &start); proto[1] = sdp_list_append(proto[1], sh); eh = sdp_data_alloc(SDP_UINT16, &end); proto[1] = sdp_list_append(proto[1], eh); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); sdp_data_free(psm); sdp_data_free(sh); sdp_data_free(eh); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(apseq, NULL); sdp_list_free(aproto, NULL); return record; } static int handle_cmp(gconstpointer a, gconstpointer b) { const struct attribute *attrib = a; uint16_t handle = GPOINTER_TO_UINT(b); return attrib->handle - handle; } static int attribute_cmp(gconstpointer a1, gconstpointer a2) { const struct attribute *attrib1 = a1; const struct attribute *attrib2 = a2; return attrib1->handle - attrib2->handle; } static struct attribute *find_svc_range(struct gatt_server *server, uint16_t start, uint16_t *end) { struct attribute *attrib; guint h = start; GList *l; if (end == NULL) return NULL; l = g_list_find_custom(server->database, GUINT_TO_POINTER(h), handle_cmp); if (!l) return NULL; attrib = l->data; if (bt_uuid_cmp(&attrib->uuid, &prim_uuid) != 0 && bt_uuid_cmp(&attrib->uuid, &snd_uuid) != 0) return NULL; *end = start; for (l = l->next; l; l = l->next) { struct attribute *a = l->data; if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) break; *end = a->handle; } return attrib; } static uint32_t attrib_create_sdp_new(struct gatt_server *server, uint16_t handle, const char *name) { sdp_record_t *record; struct attribute *a; uint16_t end = 0; uuid_t svc, gap_uuid; bdaddr_t addr; a = find_svc_range(server, handle, &end); if (a == NULL) return 0; if (a->len == 2) sdp_uuid16_create(&svc, att_get_u16(a->data)); else if (a->len == 16) sdp_uuid128_create(&svc, a->data); else return 0; record = server_record_new(&svc, handle, end); if (record == NULL) return 0; if (name != NULL) sdp_set_info_attr(record, name, "BlueZ", NULL); sdp_uuid16_create(&gap_uuid, GENERIC_ACCESS_PROFILE_ID); if (sdp_uuid_cmp(&svc, &gap_uuid) == 0) { sdp_set_url_attr(record, "http://www.bluez.org/", "http://www.bluez.org/", "http://www.bluez.org/"); } adapter_get_address(server->adapter, &addr); if (add_record_to_server(&addr, record) == 0) return record->handle; sdp_record_free(record); return 0; } static struct attribute *attrib_db_add_new(struct gatt_server *server, uint16_t handle, bt_uuid_t *uuid, int read_reqs, int write_reqs, const uint8_t *value, int len) { struct attribute *a; guint h = handle; DBG("handle=0x%04x", handle); if (g_list_find_custom(server->database, GUINT_TO_POINTER(h), handle_cmp)) return NULL; a = g_new0(struct attribute, 1); a->len = len; a->data = g_memdup(value, len); a->handle = handle; a->uuid = *uuid; a->read_reqs = read_reqs; a->write_reqs = write_reqs; server->database = g_list_insert_sorted(server->database, a, attribute_cmp); return a; } static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode, int reqs) { /* FIXME: currently, it is assumed an encrypted link is enough for * authentication. This will allow to enable the SMP negotiation once * it is on upstream kernel. High security level should be mapped * to authentication and medium to encryption permission. */ if (!channel->encrypted) channel->encrypted = g_attrib_is_encrypted(channel->attrib); if (reqs == ATT_AUTHENTICATION && !channel->encrypted) return ATT_ECODE_AUTHENTICATION; else if (reqs == ATT_AUTHORIZATION) return ATT_ECODE_AUTHORIZATION; switch (opcode) { case ATT_OP_READ_BY_GROUP_REQ: case ATT_OP_READ_BY_TYPE_REQ: case ATT_OP_READ_REQ: case ATT_OP_READ_BLOB_REQ: case ATT_OP_READ_MULTI_REQ: if (reqs == ATT_NOT_PERMITTED) return ATT_ECODE_READ_NOT_PERM; break; case ATT_OP_PREP_WRITE_REQ: case ATT_OP_WRITE_REQ: case ATT_OP_WRITE_CMD: if (reqs == ATT_NOT_PERMITTED) return ATT_ECODE_WRITE_NOT_PERM; break; } return 0; } static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start, uint16_t end, bt_uuid_t *uuid, uint8_t *pdu, int len) { struct att_data_list *adl; struct attribute *a; struct group_elem *cur, *old = NULL; GSList *l, *groups; GList *dl, *database; uint16_t length, last_handle, last_size = 0; uint8_t status; int i; if (start > end || start == 0x0000) return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start, ATT_ECODE_INVALID_HANDLE, pdu, len); /* * Only <> and <> grouping * types may be used in the Read By Group Type Request. */ if (bt_uuid_cmp(uuid, &prim_uuid) != 0 && bt_uuid_cmp(uuid, &snd_uuid) != 0) return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, 0x0000, ATT_ECODE_UNSUPP_GRP_TYPE, pdu, len); last_handle = end; database = channel->server->database; for (dl = database, groups = NULL, cur = NULL; dl; dl = dl->next) { a = dl->data; if (a->handle < start) continue; if (a->handle >= end) break; /* The old group ends when a new one starts */ if (old && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)) { old->end = last_handle; old = NULL; } if (bt_uuid_cmp(&a->uuid, uuid) != 0) { /* Still inside a service, update its last handle */ if (old) last_handle = a->handle; continue; } if (last_size && (last_size != a->len)) break; status = att_check_reqs(channel, ATT_OP_READ_BY_GROUP_REQ, a->read_reqs); if (status == 0x00 && a->read_cb) status = a->read_cb(a, channel->device, a->cb_user_data); if (status) { g_slist_free_full(groups, g_free); return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, a->handle, status, pdu, len); } cur = g_new0(struct group_elem, 1); cur->handle = a->handle; cur->data = a->data; cur->len = a->len; /* Attribute Grouping Type found */ groups = g_slist_append(groups, cur); last_size = a->len; old = cur; last_handle = cur->handle; } if (groups == NULL) return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start, ATT_ECODE_ATTR_NOT_FOUND, pdu, len); if (dl == NULL) cur->end = a->handle; else cur->end = last_handle; length = g_slist_length(groups); adl = att_data_list_alloc(length, last_size + 4); for (i = 0, l = groups; l; l = l->next, i++) { uint8_t *value; cur = l->data; value = (void *) adl->data[i]; att_put_u16(cur->handle, value); att_put_u16(cur->end, &value[2]); /* Attribute Value */ memcpy(&value[4], cur->data, cur->len); } length = enc_read_by_grp_resp(adl, pdu, len); att_data_list_free(adl); g_slist_free_full(groups, g_free); return length; } static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start, uint16_t end, bt_uuid_t *uuid, uint8_t *pdu, int len) { struct att_data_list *adl; GSList *l, *types; GList *dl, *database; struct attribute *a; uint16_t num, length; uint8_t status; int i; if (start > end || start == 0x0000) return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start, ATT_ECODE_INVALID_HANDLE, pdu, len); database = channel->server->database; for (dl = database, length = 0, types = NULL; dl; dl = dl->next) { a = dl->data; if (a->handle < start) continue; if (a->handle > end) break; if (bt_uuid_cmp(&a->uuid, uuid) != 0) continue; status = att_check_reqs(channel, ATT_OP_READ_BY_TYPE_REQ, a->read_reqs); if (status == 0x00 && a->read_cb) status = a->read_cb(a, channel->device, a->cb_user_data); if (status) { g_slist_free(types); return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, a->handle, status, pdu, len); } /* All elements must have the same length */ if (length == 0) length = a->len; else if (a->len != length) break; types = g_slist_append(types, a); } if (types == NULL) return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start, ATT_ECODE_ATTR_NOT_FOUND, pdu, len); num = g_slist_length(types); /* Handle length plus attribute value length */ length += 2; adl = att_data_list_alloc(num, length); for (i = 0, l = types; l; i++, l = l->next) { uint8_t *value; a = l->data; value = (void *) adl->data[i]; att_put_u16(a->handle, value); /* Attribute Value */ memcpy(&value[2], a->data, a->len); } length = enc_read_by_type_resp(adl, pdu, len); att_data_list_free(adl); g_slist_free(types); return length; } static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end, uint8_t *pdu, int len) { struct attribute *a; struct att_data_list *adl; GSList *l, *info; GList *dl, *database; uint8_t format, last_type = BT_UUID_UNSPEC; uint16_t length, num; int i; if (start > end || start == 0x0000) return enc_error_resp(ATT_OP_FIND_INFO_REQ, start, ATT_ECODE_INVALID_HANDLE, pdu, len); database = channel->server->database; for (dl = database, info = NULL, num = 0; dl; dl = dl->next) { a = dl->data; if (a->handle < start) continue; if (a->handle > end) break; if (last_type == BT_UUID_UNSPEC) last_type = a->uuid.type; if (a->uuid.type != last_type) break; info = g_slist_append(info, a); num++; last_type = a->uuid.type; } if (info == NULL) return enc_error_resp(ATT_OP_FIND_INFO_REQ, start, ATT_ECODE_ATTR_NOT_FOUND, pdu, len); if (last_type == BT_UUID16) { length = 2; format = 0x01; } else if (last_type == BT_UUID128) { length = 16; format = 0x02; } else { g_slist_free(info); return 0; } adl = att_data_list_alloc(num, length + 2); for (i = 0, l = info; l; i++, l = l->next) { uint8_t *value; a = l->data; value = (void *) adl->data[i]; att_put_u16(a->handle, value); /* Attribute Value */ att_put_uuid(a->uuid, &value[2]); } length = enc_find_info_resp(format, adl, pdu, len); att_data_list_free(adl); g_slist_free(info); return length; } static int find_by_type(struct gatt_channel *channel, uint16_t start, uint16_t end, bt_uuid_t *uuid, const uint8_t *value, int vlen, uint8_t *opdu, int mtu) { struct attribute *a; struct att_range *range; GSList *matches; GList *dl, *database; int len; if (start > end || start == 0x0000) return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start, ATT_ECODE_INVALID_HANDLE, opdu, mtu); /* Searching first requested handle number */ database = channel->server->database; for (dl = database, matches = NULL, range = NULL; dl; dl = dl->next) { a = dl->data; if (a->handle < start) continue; if (a->handle > end) break; /* Primary service? Attribute value matches? */ if ((bt_uuid_cmp(&a->uuid, uuid) == 0) && (a->len == vlen) && (memcmp(a->data, value, vlen) == 0)) { range = g_new0(struct att_range, 1); range->start = a->handle; /* It is allowed to have end group handle the same as * start handle, for groups with only one attribute. */ range->end = a->handle; matches = g_slist_append(matches, range); } else if (range) { /* Update the last found handle or reset the pointer * to track that a new group started: Primary or * Secondary service. */ if (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) range = NULL; else range->end = a->handle; } } if (matches == NULL) return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start, ATT_ECODE_ATTR_NOT_FOUND, opdu, mtu); len = enc_find_by_type_resp(matches, opdu, mtu); g_slist_free_full(matches, g_free); return len; } static uint16_t read_value(struct gatt_channel *channel, uint16_t handle, uint8_t *pdu, int len) { struct attribute *a; uint8_t status; GList *l; uint16_t cccval; uint8_t bdaddr_type; guint h = handle; l = g_list_find_custom(channel->server->database, GUINT_TO_POINTER(h), handle_cmp); if (!l) return enc_error_resp(ATT_OP_READ_REQ, handle, ATT_ECODE_INVALID_HANDLE, pdu, len); a = l->data; bdaddr_type = device_get_addr_type(channel->device); if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 && read_device_ccc(&channel->src, &channel->dst, bdaddr_type, handle, &cccval) == 0) { uint8_t config[2]; att_put_u16(cccval, config); return enc_read_resp(config, sizeof(config), pdu, len); } status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_reqs); if (status == 0x00 && a->read_cb) status = a->read_cb(a, channel->device, a->cb_user_data); if (status) return enc_error_resp(ATT_OP_READ_REQ, handle, status, pdu, len); return enc_read_resp(a->data, a->len, pdu, len); } static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle, uint16_t offset, uint8_t *pdu, int len) { struct attribute *a; uint8_t status; GList *l; uint16_t cccval; uint8_t bdaddr_type; guint h = handle; l = g_list_find_custom(channel->server->database, GUINT_TO_POINTER(h), handle_cmp); if (!l) return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, ATT_ECODE_INVALID_HANDLE, pdu, len); a = l->data; if (a->len <= offset) return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, ATT_ECODE_INVALID_OFFSET, pdu, len); bdaddr_type = device_get_addr_type(channel->device); if (bt_uuid_cmp(&ccc_uuid, &a->uuid) == 0 && read_device_ccc(&channel->src, &channel->dst, bdaddr_type, handle, &cccval) == 0) { uint8_t config[2]; att_put_u16(cccval, config); return enc_read_blob_resp(config, sizeof(config), offset, pdu, len); } status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_reqs); if (status == 0x00 && a->read_cb) status = a->read_cb(a, channel->device, a->cb_user_data); if (status) return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, status, pdu, len); return enc_read_blob_resp(a->data, a->len, offset, pdu, len); } static uint16_t write_value(struct gatt_channel *channel, uint16_t handle, const uint8_t *value, int vlen, uint8_t *pdu, int len) { struct attribute *a; uint8_t status; GList *l; guint h = handle; l = g_list_find_custom(channel->server->database, GUINT_TO_POINTER(h), handle_cmp); if (!l) return enc_error_resp(ATT_OP_WRITE_REQ, handle, ATT_ECODE_INVALID_HANDLE, pdu, len); a = l->data; status = att_check_reqs(channel, ATT_OP_WRITE_REQ, a->write_reqs); if (status) return enc_error_resp(ATT_OP_WRITE_REQ, handle, status, pdu, len); if (bt_uuid_cmp(&ccc_uuid, &a->uuid) != 0) { attrib_db_update(channel->server->adapter, handle, NULL, value, vlen, NULL); if (a->write_cb) { status = a->write_cb(a, channel->device, a->cb_user_data); if (status) return enc_error_resp(ATT_OP_WRITE_REQ, handle, status, pdu, len); } } else { uint16_t cccval = att_get_u16(value); uint8_t bdaddr_type = device_get_addr_type(channel->device); write_device_ccc(&channel->src, &channel->dst, bdaddr_type, handle, cccval); } return enc_write_resp(pdu, len); } static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu, uint8_t *pdu, int len) { GError *gerr = NULL; GIOChannel *io; uint16_t imtu; if (mtu < ATT_DEFAULT_LE_MTU) return enc_error_resp(ATT_OP_MTU_REQ, 0, ATT_ECODE_REQ_NOT_SUPP, pdu, len); io = g_attrib_get_channel(channel->attrib); bt_io_get(io, BT_IO_L2CAP, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID); if (gerr) return enc_error_resp(ATT_OP_MTU_REQ, 0, ATT_ECODE_UNLIKELY, pdu, len); channel->mtu = MIN(mtu, imtu); g_attrib_set_mtu(channel->attrib, channel->mtu); return enc_mtu_resp(imtu, pdu, len); } static void channel_remove(struct gatt_channel *channel) { channel->server->clients = g_slist_remove(channel->server->clients, channel); channel_free(channel); } static gboolean channel_watch_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { channel_remove(user_data); return FALSE; } static void channel_handler(const uint8_t *ipdu, uint16_t len, gpointer user_data) { struct gatt_channel *channel = user_data; uint8_t opdu[ATT_MAX_MTU], value[ATT_MAX_MTU]; uint16_t length, start, end, mtu, offset; bt_uuid_t uuid; uint8_t status = 0; int vlen; DBG("op 0x%02x", ipdu[0]); switch (ipdu[0]) { case ATT_OP_READ_BY_GROUP_REQ: length = dec_read_by_grp_req(ipdu, len, &start, &end, &uuid); if (length == 0) { status = ATT_ECODE_INVALID_PDU; goto done; } length = read_by_group(channel, start, end, &uuid, opdu, channel->mtu); break; case ATT_OP_READ_BY_TYPE_REQ: length = dec_read_by_type_req(ipdu, len, &start, &end, &uuid); if (length == 0) { status = ATT_ECODE_INVALID_PDU; goto done; } length = read_by_type(channel, start, end, &uuid, opdu, channel->mtu); break; case ATT_OP_READ_REQ: length = dec_read_req(ipdu, len, &start); if (length == 0) { status = ATT_ECODE_INVALID_PDU; goto done; } length = read_value(channel, start, opdu, channel->mtu); break; case ATT_OP_READ_BLOB_REQ: length = dec_read_blob_req(ipdu, len, &start, &offset); if (length == 0) { status = ATT_ECODE_INVALID_PDU; goto done; } length = read_blob(channel, start, offset, opdu, channel->mtu); break; case ATT_OP_MTU_REQ: if (!channel->le) { status = ATT_ECODE_REQ_NOT_SUPP; goto done; } length = dec_mtu_req(ipdu, len, &mtu); if (length == 0) { status = ATT_ECODE_INVALID_PDU; goto done; } length = mtu_exchange(channel, mtu, opdu, channel->mtu); break; case ATT_OP_FIND_INFO_REQ: length = dec_find_info_req(ipdu, len, &start, &end); if (length == 0) { status = ATT_ECODE_INVALID_PDU; goto done; } length = find_info(channel, start, end, opdu, channel->mtu); break; case ATT_OP_WRITE_REQ: length = dec_write_req(ipdu, len, &start, value, &vlen); if (length == 0) { status = ATT_ECODE_INVALID_PDU; goto done; } length = write_value(channel, start, value, vlen, opdu, channel->mtu); break; case ATT_OP_WRITE_CMD: length = dec_write_cmd(ipdu, len, &start, value, &vlen); if (length > 0) write_value(channel, start, value, vlen, opdu, channel->mtu); return; case ATT_OP_FIND_BY_TYPE_REQ: length = dec_find_by_type_req(ipdu, len, &start, &end, &uuid, value, &vlen); if (length == 0) { status = ATT_ECODE_INVALID_PDU; goto done; } length = find_by_type(channel, start, end, &uuid, value, vlen, opdu, channel->mtu); break; case ATT_OP_HANDLE_CNF: return; case ATT_OP_HANDLE_IND: case ATT_OP_HANDLE_NOTIFY: /* The attribute client is already handling these */ return; case ATT_OP_READ_MULTI_REQ: case ATT_OP_PREP_WRITE_REQ: case ATT_OP_EXEC_WRITE_REQ: default: DBG("Unsupported request 0x%02x", ipdu[0]); status = ATT_ECODE_REQ_NOT_SUPP; goto done; } if (length == 0) status = ATT_ECODE_IO; done: if (status) length = enc_error_resp(ipdu[0], 0x0000, status, opdu, channel->mtu); g_attrib_send(channel->attrib, 0, opdu[0], opdu, length, NULL, NULL, NULL); } guint attrib_channel_attach(GAttrib *attrib) { struct gatt_server *server; struct btd_device *device; struct gatt_channel *channel; GIOChannel *io; GError *gerr = NULL; char addr[18]; uint16_t cid; guint mtu = 0; io = g_attrib_get_channel(attrib); channel = g_new0(struct gatt_channel, 1); bt_io_get(io, BT_IO_L2CAP, &gerr, BT_IO_OPT_SOURCE_BDADDR, &channel->src, BT_IO_OPT_DEST_BDADDR, &channel->dst, BT_IO_OPT_CID, &cid, BT_IO_OPT_IMTU, &mtu, BT_IO_OPT_INVALID); if (gerr) { error("bt_io_get: %s", gerr->message); g_error_free(gerr); g_free(channel); return 0; } server = find_gatt_server(&channel->src); if (server == NULL) { char src[18]; ba2str(&channel->src, src); error("No GATT server found in %s", src); g_free(channel); return 0; } channel->server = server; ba2str(&channel->dst, addr); device = adapter_find_device(server->adapter, addr); if (device == NULL || device_is_bonded(device) == FALSE) delete_device_ccc(&channel->src, &channel->dst); if (cid != ATT_CID) { channel->le = FALSE; channel->mtu = mtu; } else { channel->le = TRUE; channel->mtu = ATT_DEFAULT_LE_MTU; } channel->attrib = g_attrib_ref(attrib); channel->id = g_attrib_register(channel->attrib, GATTRIB_ALL_REQS, channel_handler, channel, NULL); channel->cleanup_id = g_io_add_watch(io, G_IO_HUP, channel_watch_cb, channel); channel->device = btd_device_ref(device); server->clients = g_slist_append(server->clients, channel); return channel->id; } static gint channel_id_cmp(gconstpointer data, gconstpointer user_data) { const struct gatt_channel *channel = data; guint id = GPOINTER_TO_UINT(user_data); return channel->id - id; } gboolean attrib_channel_detach(GAttrib *attrib, guint id) { struct gatt_server *server; struct gatt_channel *channel; GError *gerr = NULL; GIOChannel *io; bdaddr_t src; GSList *l; io = g_attrib_get_channel(attrib); bt_io_get(io, BT_IO_L2CAP, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_INVALID); if (gerr != NULL) { error("bt_io_get: %s", gerr->message); g_error_free(gerr); return FALSE; } server = find_gatt_server(&src); if (server == NULL) return FALSE; l = g_slist_find_custom(server->clients, GUINT_TO_POINTER(id), channel_id_cmp); if (!l) return FALSE; channel = l->data; g_attrib_unregister(channel->attrib, channel->id); channel_remove(channel); return TRUE; } static void connect_event(GIOChannel *io, GError *gerr, void *user_data) { GAttrib *attrib; if (gerr) { error("%s", gerr->message); return; } attrib = g_attrib_new(io); attrib_channel_attach(attrib); g_attrib_unref(attrib); } static void confirm_event(GIOChannel *io, void *user_data) { GError *gerr = NULL; if (bt_io_accept(io, connect_event, user_data, NULL, &gerr) == FALSE) { error("bt_io_accept: %s", gerr->message); g_error_free(gerr); g_io_channel_unref(io); } return; } static gboolean register_core_services(struct gatt_server *server) { uint8_t atval[256]; bt_uuid_t uuid; uint16_t appearance = 0x0000; /* GAP service: primary service definition */ bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID); att_put_u16(GENERIC_ACCESS_PROFILE_ID, &atval[0]); attrib_db_add_new(server, 0x0001, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2); /* GAP service: device name characteristic */ server->name_handle = 0x0006; bt_uuid16_create(&uuid, GATT_CHARAC_UUID); atval[0] = ATT_CHAR_PROPER_READ; att_put_u16(server->name_handle, &atval[1]); att_put_u16(GATT_CHARAC_DEVICE_NAME, &atval[3]); attrib_db_add_new(server, 0x0004, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5); /* GAP service: device name attribute */ bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME); attrib_db_add_new(server, server->name_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED, NULL, 0); /* GAP service: device appearance characteristic */ server->appearance_handle = 0x0008; bt_uuid16_create(&uuid, GATT_CHARAC_UUID); atval[0] = ATT_CHAR_PROPER_READ; att_put_u16(server->appearance_handle, &atval[1]); att_put_u16(GATT_CHARAC_APPEARANCE, &atval[3]); attrib_db_add_new(server, 0x0007, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5); /* GAP service: device appearance attribute */ bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE); att_put_u16(appearance, &atval[0]); attrib_db_add_new(server, server->appearance_handle, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2); server->gap_sdp_handle = attrib_create_sdp_new(server, 0x0001, "Generic Access Profile"); if (server->gap_sdp_handle == 0) { error("Failed to register GAP service record"); return FALSE; } /* GATT service: primary service definition */ bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID); att_put_u16(GENERIC_ATTRIB_PROFILE_ID, &atval[0]); attrib_db_add_new(server, 0x0010, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2); server->gatt_sdp_handle = attrib_create_sdp_new(server, 0x0010, "Generic Attribute Profile"); if (server->gatt_sdp_handle == 0) { error("Failed to register GATT service record"); return FALSE; } return TRUE; } int btd_adapter_gatt_server_start(struct btd_adapter *adapter) { struct gatt_server *server; GError *gerr = NULL; bdaddr_t addr; DBG("Start GATT server in hci%d", adapter_get_dev_id(adapter)); server = g_new0(struct gatt_server, 1); server->adapter = btd_adapter_ref(adapter); adapter_get_address(server->adapter, &addr); /* BR/EDR socket */ server->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, NULL, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &addr, BT_IO_OPT_PSM, ATT_PSM, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (server->l2cap_io == NULL) { error("%s", gerr->message); g_error_free(gerr); gatt_server_free(server); return -1; } if (!register_core_services(server)) { gatt_server_free(server); return -1; } /* LE socket */ server->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, &server->le_io, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &addr, BT_IO_OPT_CID, ATT_CID, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (server->le_io == NULL) { error("%s", gerr->message); g_error_free(gerr); /* Doesn't have LE support, continue */ } servers = g_slist_prepend(servers, server); return 0; } void btd_adapter_gatt_server_stop(struct btd_adapter *adapter) { struct gatt_server *server; GSList *l; l = g_slist_find_custom(servers, adapter, adapter_cmp); if (l == NULL) return; DBG("Stop GATT server in hci%d", adapter_get_dev_id(adapter)); server = l->data; servers = g_slist_remove(servers, server); gatt_server_free(server); } uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle, const char *name) { GSList *l; l = g_slist_find_custom(servers, adapter, adapter_cmp); if (l == NULL) return 0; return attrib_create_sdp_new(l->data, handle, name); } void attrib_free_sdp(uint32_t sdp_handle) { remove_record_from_server(sdp_handle); } static uint16_t find_uuid16_avail(struct btd_adapter *adapter, uint16_t nitems) { struct gatt_server *server; uint16_t handle; GSList *l; GList *dl; l = g_slist_find_custom(servers, adapter, adapter_cmp); if (l == NULL) return 0; server = l->data; if (server->database == NULL) return 0x0001; for (dl = server->database, handle = 0x0001; dl; dl = dl->next) { struct attribute *a = dl->data; if ((bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || bt_uuid_cmp(&a->uuid, &snd_uuid) == 0) && a->handle - handle >= nitems) /* Note: the range above excludes the current handle */ return handle; if (a->len == 16 && (bt_uuid_cmp(&a->uuid, &prim_uuid) == 0 || bt_uuid_cmp(&a->uuid, &snd_uuid) == 0)) { /* 128 bit UUID service definition */ return 0; } if (a->handle == 0xffff) return 0; handle = a->handle + 1; } if (0xffff - handle + 1 >= nitems) return handle; return 0; } static uint16_t find_uuid128_avail(struct btd_adapter *adapter, uint16_t nitems) { uint16_t handle = 0, end = 0xffff; struct gatt_server *server; GList *dl; GSList *l; l = g_slist_find_custom(servers, adapter, adapter_cmp); if (l == NULL) return 0; server = l->data; if (server->database == NULL) return 0xffff - nitems + 1; for (dl = g_list_last(server->database); dl; dl = dl->prev) { struct attribute *a = dl->data; if (handle == 0) handle = a->handle; if (bt_uuid_cmp(&a->uuid, &prim_uuid) != 0 && bt_uuid_cmp(&a->uuid, &snd_uuid) != 0) continue; if (end - handle >= nitems) return end - nitems + 1; if (a->len == 2) { /* 16 bit UUID service definition */ return 0; } if (a->handle == 0x0001) return 0; end = a->handle - 1; handle = 0; } if (end - 0x0001 >= nitems) return end - nitems + 1; return 0; } uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid, uint16_t nitems) { g_assert(nitems > 0); if (svc_uuid->type == BT_UUID16) return find_uuid16_avail(adapter, nitems); else if (svc_uuid->type == BT_UUID128) return find_uuid128_avail(adapter, nitems); else { char uuidstr[MAX_LEN_UUID_STR]; bt_uuid_to_string(svc_uuid, uuidstr, MAX_LEN_UUID_STR); error("Service uuid: %s is neither a 16-bit nor a 128-bit uuid", uuidstr); return 0; } } struct attribute *attrib_db_add(struct btd_adapter *adapter, uint16_t handle, bt_uuid_t *uuid, int read_reqs, int write_reqs, const uint8_t *value, int len) { GSList *l; l = g_slist_find_custom(servers, adapter, adapter_cmp); if (l == NULL) return NULL; return attrib_db_add_new(l->data, handle, uuid, read_reqs, write_reqs, value, len); } int attrib_db_update(struct btd_adapter *adapter, uint16_t handle, bt_uuid_t *uuid, const uint8_t *value, int len, struct attribute **attr) { struct gatt_server *server; struct attribute *a; GSList *l; GList *dl; guint h = handle; l = g_slist_find_custom(servers, adapter, adapter_cmp); if (l == NULL) return -ENOENT; server = l->data; DBG("handle=0x%04x", handle); dl = g_list_find_custom(server->database, GUINT_TO_POINTER(h), handle_cmp); if (dl == NULL) return -ENOENT; a = dl->data; a->data = g_try_realloc(a->data, len); if (len && a->data == NULL) return -ENOMEM; a->len = len; memcpy(a->data, value, len); if (uuid != NULL) a->uuid = *uuid; if (attr) *attr = a; return 0; } int attrib_db_del(struct btd_adapter *adapter, uint16_t handle) { struct gatt_server *server; struct attribute *a; GSList *l; GList *dl; guint h = handle; l = g_slist_find_custom(servers, adapter, adapter_cmp); if (l == NULL) return -ENOENT; server = l->data; DBG("handle=0x%04x", handle); dl = g_list_find_custom(server->database, GUINT_TO_POINTER(h), handle_cmp); if (dl == NULL) return -ENOENT; a = dl->data; server->database = g_list_remove(server->database, a); g_free(a->data); g_free(a); return 0; } int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid, const uint8_t *value, int len) { struct gatt_server *server; uint16_t handle; GSList *l; l = g_slist_find_custom(servers, adapter, adapter_cmp); if (l == NULL) return -ENOENT; server = l->data; /* FIXME: Missing Privacy and Reconnection Address */ switch (uuid) { case GATT_CHARAC_DEVICE_NAME: handle = server->name_handle; break; case GATT_CHARAC_APPEARANCE: handle = server->appearance_handle; break; default: return -ENOSYS; } return attrib_db_update(adapter, handle, NULL, value, len, NULL); } bluez-4.101/src/sdpd-server.c0000644000000000000000000001451411766125764012744 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2001-2002 Nokia Corporation * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * Copyright (C) 2002-2003 Stephen Crane * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include "hcid.h" #include "log.h" #include "sdpd.h" static guint l2cap_id = 0, unix_id = 0; static int l2cap_sock, unix_sock; /* * SDP server initialization on startup includes creating the * l2cap and unix sockets over which discovery and registration clients * access us respectively */ static int init_server(uint16_t mtu, int master, int compat) { struct l2cap_options opts; struct sockaddr_l2 l2addr; struct sockaddr_un unaddr; socklen_t optlen; /* Register the public browse group root */ register_public_browse_group(); /* Register the SDP server's service record */ register_server_service(); /* Create L2CAP socket */ l2cap_sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP); if (l2cap_sock < 0) { error("opening L2CAP socket: %s", strerror(errno)); return -1; } memset(&l2addr, 0, sizeof(l2addr)); l2addr.l2_family = AF_BLUETOOTH; bacpy(&l2addr.l2_bdaddr, BDADDR_ANY); l2addr.l2_psm = htobs(SDP_PSM); if (bind(l2cap_sock, (struct sockaddr *) &l2addr, sizeof(l2addr)) < 0) { error("binding L2CAP socket: %s", strerror(errno)); return -1; } if (master) { int opt = L2CAP_LM_MASTER; if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0) { error("setsockopt: %s", strerror(errno)); return -1; } } if (mtu > 0) { memset(&opts, 0, sizeof(opts)); optlen = sizeof(opts); if (getsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, &optlen) < 0) { error("getsockopt: %s", strerror(errno)); return -1; } opts.omtu = mtu; opts.imtu = mtu; if (setsockopt(l2cap_sock, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts)) < 0) { error("setsockopt: %s", strerror(errno)); return -1; } } if (listen(l2cap_sock, 5) < 0) { error("listen: %s", strerror(errno)); return -1; } if (!compat) { unix_sock = -1; return 0; } /* Create local Unix socket */ unix_sock = socket(PF_UNIX, SOCK_STREAM, 0); if (unix_sock < 0) { error("opening UNIX socket: %s", strerror(errno)); return -1; } memset(&unaddr, 0, sizeof(unaddr)); unaddr.sun_family = AF_UNIX; strcpy(unaddr.sun_path, SDP_UNIX_PATH); unlink(unaddr.sun_path); if (bind(unix_sock, (struct sockaddr *) &unaddr, sizeof(unaddr)) < 0) { error("binding UNIX socket: %s", strerror(errno)); return -1; } if (listen(unix_sock, 5) < 0) { error("listen UNIX socket: %s", strerror(errno)); return -1; } chmod(SDP_UNIX_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH); return 0; } static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer data) { sdp_pdu_hdr_t hdr; uint8_t *buf; int sk, len, size; if (cond & G_IO_NVAL) return FALSE; sk = g_io_channel_unix_get_fd(chan); if (cond & (G_IO_HUP | G_IO_ERR)) { sdp_svcdb_collect_all(sk); return FALSE; } len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK); if (len <= 0) { sdp_svcdb_collect_all(sk); return FALSE; } size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen); buf = malloc(size); if (!buf) return TRUE; len = recv(sk, buf, size, 0); if (len <= 0) { sdp_svcdb_collect_all(sk); free(buf); return FALSE; } handle_request(sk, buf, len); return TRUE; } static gboolean io_accept_event(GIOChannel *chan, GIOCondition cond, gpointer data) { GIOChannel *io; int nsk; if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) return FALSE; if (data == &l2cap_sock) { struct sockaddr_l2 addr; socklen_t len = sizeof(addr); nsk = accept(l2cap_sock, (struct sockaddr *) &addr, &len); } else if (data == &unix_sock) { struct sockaddr_un addr; socklen_t len = sizeof(addr); nsk = accept(unix_sock, (struct sockaddr *) &addr, &len); } else return FALSE; if (nsk < 0) { error("Can't accept connection: %s", strerror(errno)); return TRUE; } io = g_io_channel_unix_new(nsk); g_io_channel_set_close_on_unref(io, TRUE); g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, io_session_event, data); g_io_channel_unref(io); return TRUE; } int start_sdp_server(uint16_t mtu, uint32_t flags) { int compat = flags & SDP_SERVER_COMPAT; int master = flags & SDP_SERVER_MASTER; GIOChannel *io; info("Starting SDP server"); if (init_server(mtu, master, compat) < 0) { error("Server initialization failed"); return -1; } if (main_opts.did_source > 0) register_device_id(); io = g_io_channel_unix_new(l2cap_sock); g_io_channel_set_close_on_unref(io, TRUE); l2cap_id = g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, io_accept_event, &l2cap_sock); g_io_channel_unref(io); if (compat && unix_sock > fileno(stderr)) { io = g_io_channel_unix_new(unix_sock); g_io_channel_set_close_on_unref(io, TRUE); unix_id = g_io_add_watch(io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, io_accept_event, &unix_sock); g_io_channel_unref(io); } return 0; } void stop_sdp_server(void) { info("Stopping SDP server"); sdp_svcdb_reset(); if (unix_id > 0) g_source_remove(unix_id); if (l2cap_id > 0) g_source_remove(l2cap_id); l2cap_id = unix_id = 0; l2cap_sock = unix_sock = -1; } bluez-4.101/src/log.h0000644000000000000000000000376711766125764011304 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ void info(const char *format, ...) __attribute__((format(printf, 1, 2))); void warn(const char *format, ...) __attribute__((format(printf, 1, 2))); void error(const char *format, ...) __attribute__((format(printf, 1, 2))); void btd_debug(const char *format, ...) __attribute__((format(printf, 1, 2))); void __btd_log_init(const char *debug, int detach); void __btd_log_cleanup(void); void __btd_toggle_debug(void); struct btd_debug_desc { const char *file; #define BTD_DEBUG_FLAG_DEFAULT (0) #define BTD_DEBUG_FLAG_PRINT (1 << 0) unsigned int flags; } __attribute__((aligned(8))); void __btd_enable_debug(struct btd_debug_desc *start, struct btd_debug_desc *stop); /** * DBG: * @fmt: format string * @arg...: list of arguments * * Simple macro around btd_debug() which also include the function * name it is called in. */ #define DBG(fmt, arg...) do { \ static struct btd_debug_desc __btd_debug_desc \ __attribute__((used, section("__debug"), aligned(8))) = { \ .file = __FILE__, .flags = BTD_DEBUG_FLAG_DEFAULT, \ }; \ if (__btd_debug_desc.flags & BTD_DEBUG_FLAG_PRINT) \ btd_debug("%s:%s() " fmt, __FILE__, __FUNCTION__ , ## arg); \ } while (0) bluez-4.101/src/plugin.h0000644000000000000000000000362111766125764012006 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define BLUETOOTH_PLUGIN_PRIORITY_LOW -100 #define BLUETOOTH_PLUGIN_PRIORITY_DEFAULT 0 #define BLUETOOTH_PLUGIN_PRIORITY_HIGH 100 struct bluetooth_plugin_desc { const char *name; const char *version; int priority; int (*init) (void); void (*exit) (void); void *debug_start; void *debug_stop; }; #ifdef BLUETOOTH_PLUGIN_BUILTIN #define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \ struct bluetooth_plugin_desc __bluetooth_builtin_ ## name = { \ #name, version, priority, init, exit \ }; #else #define BLUETOOTH_PLUGIN_DEFINE(name, version, priority, init, exit) \ extern struct btd_debug_desc __start___debug[] \ __attribute__ ((weak, visibility("hidden"))); \ extern struct btd_debug_desc __stop___debug[] \ __attribute__ ((weak, visibility("hidden"))); \ extern struct bluetooth_plugin_desc bluetooth_plugin_desc \ __attribute__ ((visibility("default"))); \ struct bluetooth_plugin_desc bluetooth_plugin_desc = { \ #name, version, priority, init, exit, \ __start___debug, __stop___debug \ }; #endif bluez-4.101/src/sdp-client.h0000644000000000000000000000237211766125764012554 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ typedef void (*bt_callback_t) (sdp_list_t *recs, int err, gpointer user_data); typedef void (*bt_destroy_t) (gpointer user_data); int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst, uuid_t *uuid, bt_callback_t cb, void *user_data, bt_destroy_t destroy); int bt_cancel_discovery(const bdaddr_t *src, const bdaddr_t *dst); void bt_clear_cached_session(const bdaddr_t *src, const bdaddr_t *dst); bluez-4.101/src/main.conf0000644000000000000000000000461011766125764012131 00000000000000[General] # List of plugins that should not be loaded on bluetoothd startup #DisablePlugins = network,input # Default adaper name # %h - substituted for hostname # %d - substituted for adapter id Name = %h-%d # Default device class. Only the major and minor device class bits are # considered. Class = 0x000100 # How long to stay in discoverable mode before going back to non-discoverable # The value is in seconds. Default is 180, i.e. 3 minutes. # 0 = disable timer, i.e. stay discoverable forever DiscoverableTimeout = 0 # How long to stay in pairable mode before going back to non-discoverable # The value is in seconds. Default is 0. # 0 = disable timer, i.e. stay pairable forever PairableTimeout = 0 # Use some other page timeout than the controller default one # which is 16384 (10 seconds). PageTimeout = 8192 # Automatic connection for bonded devices driven by platform/user events. # If a platform plugin uses this mechanism, automatic connections will be # enabled during the interval defined below. Initially, this feature # intends to be used to establish connections to ATT channels. AutoConnectTimeout = 60 # What value should be assumed for the adapter Powered property when # SetProperty(Powered, ...) hasn't been called yet. Defaults to true InitiallyPowered = true # Remember the previously stored Powered state when initializing adapters RememberPowered = true # Use vendor id source (assigner), vendor, product and version information for # DID profile support. The values are separated by ":" and assigner, VID, PID # and version. # Possible vendor id source values: bluetooth, usb (defaults to usb) #DeviceID = bluetooth:1234:5678:abcd # Do reverse service discovery for previously unknown devices that connect to # us. This option is really only needed for qualification since the BITE tester # doesn't like us doing reverse SDP for some test cases (though there could in # theory be other useful purposes for this too). Defaults to true. ReverseServiceDiscovery = true # Enable name resolving after inquiry. Set it to 'false' if you don't need # remote devices name and want shorter discovery cycle. Defaults to 'true'. NameResolving = true # Enable runtime persistency of debug link keys. Default is false which # makes debug link keys valid only for the duration of the connection # that they were created for. DebugKeys = false # Enable the GATT functionality. Default is false EnableGatt = false bluez-4.101/src/oui.c0000644000000000000000000000366011571052274011267 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "oui.h" /* http://standards.ieee.org/regauth/oui/oui.txt */ char *ouitocomp(const char *oui) { struct stat st; char *str, *map, *off, *end; int fd; fd = open(OUIFILE, O_RDONLY); if (fd < 0) return NULL; if (fstat(fd, &st) < 0) { close(fd); return NULL; } str = malloc(128); if (!str) { close(fd); return NULL; } memset(str, 0, 128); map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (!map || map == MAP_FAILED) { free(str); close(fd); return NULL; } off = strstr(map, oui); if (off) { off += 18; end = strpbrk(off, "\r\n"); strncpy(str, off, end - off); } else { free(str); str = NULL; } munmap(map, st.st_size); close(fd); return str; } int oui2comp(const char *oui, char *comp, size_t size) { char *tmp; tmp = ouitocomp(oui); if (!tmp) return -1; snprintf(comp, size, "%s", tmp); free(tmp); return 0; } bluez-4.101/src/adapter.h0000644000000000000000000002574011766125764012136 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #include #include #include #include #define ADAPTER_INTERFACE "org.bluez.Adapter" #define MODE_OFF 0x00 #define MODE_CONNECTABLE 0x01 #define MODE_DISCOVERABLE 0x02 #define MODE_UNKNOWN 0xff #define MAX_NAME_LENGTH 248 /* Invalid SSP passkey value used to indicate negative replies */ #define INVALID_PASSKEY 0xffffffff struct btd_adapter; struct link_key_info { bdaddr_t bdaddr; unsigned char key[16]; uint8_t type; uint8_t pin_len; }; struct smp_ltk_info { bdaddr_t bdaddr; uint8_t bdaddr_type; uint8_t authenticated; uint8_t master; uint8_t enc_size; uint16_t ediv; uint8_t rand[8]; uint8_t val[16]; }; struct remote_dev_info { bdaddr_t bdaddr; uint8_t bdaddr_type; int8_t rssi; uint32_t class; char *name; char *alias; dbus_bool_t legacy; char **uuids; size_t uuid_count; GSList *services; uint8_t flags; }; void btd_adapter_start(struct btd_adapter *adapter); int btd_adapter_stop(struct btd_adapter *adapter); void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode, uint8_t *on_mode, uint16_t *discoverable_timeout, gboolean *pairable); void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major, uint8_t *minor); const char *btd_adapter_get_name(struct btd_adapter *adapter); struct btd_device *adapter_get_device(DBusConnection *conn, struct btd_adapter *adapter, const char *address); struct btd_device *adapter_find_device(struct btd_adapter *adapter, const char *dest); void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter, struct btd_device *device, gboolean remove_storage); struct btd_adapter *adapter_create(DBusConnection *conn, int id); gboolean adapter_init(struct btd_adapter *adapter, gboolean up); void adapter_remove(struct btd_adapter *adapter); void adapter_set_allow_name_changes(struct btd_adapter *adapter, gboolean allow_name_changes); void adapter_set_discovering(struct btd_adapter *adapter, gboolean discovering); uint16_t adapter_get_dev_id(struct btd_adapter *adapter); const gchar *adapter_get_path(struct btd_adapter *adapter); void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr); struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr); void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type, int8_t rssi, uint8_t confirm_name, uint8_t *data, uint8_t data_len); void adapter_emit_device_found(struct btd_adapter *adapter, struct remote_dev_info *dev); void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode); int adapter_set_name(struct btd_adapter *adapter, const char *name); void adapter_name_changed(struct btd_adapter *adapter, const char *name); void adapter_service_insert(struct btd_adapter *adapter, void *rec); void adapter_service_remove(struct btd_adapter *adapter, void *rec); void btd_adapter_class_changed(struct btd_adapter *adapter, uint32_t new_class); void btd_adapter_pairable_changed(struct btd_adapter *adapter, gboolean pairable); struct agent *adapter_get_agent(struct btd_adapter *adapter); void adapter_add_connection(struct btd_adapter *adapter, struct btd_device *device); void adapter_remove_connection(struct btd_adapter *adapter, struct btd_device *device); gboolean adapter_has_discov_sessions(struct btd_adapter *adapter); struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter); void btd_adapter_unref(struct btd_adapter *adapter); int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major, uint8_t minor); struct btd_adapter_driver { const char *name; int (*probe) (struct btd_adapter *adapter); void (*remove) (struct btd_adapter *adapter); }; typedef void (*service_auth_cb) (DBusError *derr, void *user_data); int btd_register_adapter_driver(struct btd_adapter_driver *driver); void btd_unregister_adapter_driver(struct btd_adapter_driver *driver); int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst, const char *uuid, service_auth_cb cb, void *user_data); int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst); const char *adapter_any_get_path(void); const char *btd_adapter_any_request_path(void); void btd_adapter_any_release_path(void); gboolean adapter_powering_down(struct btd_adapter *adapter); int btd_adapter_restore_powered(struct btd_adapter *adapter); int btd_adapter_switch_online(struct btd_adapter *adapter); int btd_adapter_switch_offline(struct btd_adapter *adapter); void btd_adapter_enable_auto_connect(struct btd_adapter *adapter); typedef ssize_t (*btd_adapter_pin_cb_t) (struct btd_adapter *adapter, struct btd_device *dev, char *out, gboolean *display); void btd_adapter_register_pin_cb(struct btd_adapter *adapter, btd_adapter_pin_cb_t cb); void btd_adapter_unregister_pin_cb(struct btd_adapter *adapter, btd_adapter_pin_cb_t cb); ssize_t btd_adapter_get_pin(struct btd_adapter *adapter, struct btd_device *dev, char *pin_buf, gboolean *display); typedef void (*bt_hci_result_t) (uint8_t status, gpointer user_data); struct btd_adapter_ops { int (*setup) (void); void (*cleanup) (void); int (*set_powered) (int index, gboolean powered); int (*set_discoverable) (int index, gboolean discoverable, uint16_t timeout); int (*set_pairable) (int index, gboolean pairable); int (*start_discovery) (int index); int (*stop_discovery) (int index); int (*set_name) (int index, const char *name); int (*set_dev_class) (int index, uint8_t major, uint8_t minor); int (*set_fast_connectable) (int index, gboolean enable); int (*read_clock) (int index, bdaddr_t *bdaddr, int which, int timeout, uint32_t *clock, uint16_t *accuracy); int (*read_bdaddr) (int index, bdaddr_t *bdaddr); int (*block_device) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type); int (*unblock_device) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type); int (*get_conn_list) (int index, GSList **conns); int (*disconnect) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type); int (*remove_bonding) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type); int (*pincode_reply) (int index, bdaddr_t *bdaddr, const char *pin, size_t pin_len); int (*confirm_reply) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type, gboolean success); int (*passkey_reply) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type, uint32_t passkey); int (*encrypt_link) (int index, bdaddr_t *bdaddr, bt_hci_result_t cb, gpointer user_data); int (*set_did) (int index, uint16_t vendor, uint16_t product, uint16_t version, uint16_t source); int (*add_uuid) (int index, uuid_t *uuid, uint8_t svc_hint); int (*remove_uuid) (int index, uuid_t *uuid); int (*disable_cod_cache) (int index); int (*restore_powered) (int index); int (*load_keys) (int index, GSList *keys, gboolean debug_keys); int (*set_io_capability) (int index, uint8_t io_capability); int (*create_bonding) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type, uint8_t io_cap); int (*cancel_bonding) (int index, bdaddr_t *bdaddr); int (*read_local_oob_data) (int index); int (*add_remote_oob_data) (int index, bdaddr_t *bdaddr, uint8_t *hash, uint8_t *randomizer); int (*remove_remote_oob_data) (int index, bdaddr_t *bdaddr); int (*confirm_name) (int index, bdaddr_t *bdaddr, uint8_t bdaddr_type, gboolean name_known); int (*load_ltks) (int index, GSList *keys); }; int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority); void btd_adapter_cleanup_ops(struct btd_adapter_ops *btd_adapter_ops); int adapter_ops_setup(void); typedef void (*btd_adapter_powered_cb) (struct btd_adapter *adapter, gboolean powered); void btd_adapter_register_powered_callback(struct btd_adapter *adapter, btd_adapter_powered_cb cb); void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter, btd_adapter_powered_cb cb); /* If TRUE, enables fast connectabe, i.e. reduces page scan interval and changes * type. If FALSE, disables fast connectable, i.e. sets page scan interval and * type to default values. Valid for both connectable and discoverable modes. */ int btd_adapter_set_fast_connectable(struct btd_adapter *adapter, gboolean enable); int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr, int which, int timeout, uint32_t *clock, uint16_t *accuracy); int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type); int btd_adapter_unblock_address(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type); int btd_adapter_disconnect_device(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type); int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type); int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr, const char *pin, size_t pin_len); int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type, gboolean success); int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type, uint32_t passkey); int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr, bt_hci_result_t cb, gpointer user_data); int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor, uint16_t product, uint16_t version, uint16_t source); int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type, uint8_t io_cap); int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr); void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t status); int btd_adapter_read_local_oob_data(struct btd_adapter *adapter); int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t *hash, uint8_t *randomizer); int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter, bdaddr_t *bdaddr); int btd_adapter_gatt_server_start(struct btd_adapter *adapter); void btd_adapter_gatt_server_stop(struct btd_adapter *adapter); bluez-4.101/src/bluetooth.service.in0000644000000000000000000000026411766125764014333 00000000000000[Unit] Description=Bluetooth service [Service] Type=dbus BusName=org.bluez ExecStart=@prefix@/sbin/bluetoothd -n [Install] WantedBy=bluetooth.target Alias=dbus-org.bluez.service bluez-4.101/src/agent.c0000644000000000000000000004573211766125764011612 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "adapter.h" #include "device.h" #include "agent.h" #define REQUEST_TIMEOUT (60 * 1000) /* 60 seconds */ typedef enum { AGENT_REQUEST_PASSKEY, AGENT_REQUEST_CONFIRMATION, AGENT_REQUEST_PINCODE, AGENT_REQUEST_AUTHORIZE, AGENT_REQUEST_CONFIRM_MODE, AGENT_REQUEST_DISPLAY_PINCODE, } agent_request_type_t; struct agent { struct btd_adapter *adapter; char *name; char *path; uint8_t capability; struct agent_request *request; int exited; agent_remove_cb remove_cb; void *remove_cb_data; guint listener_id; }; struct agent_request { agent_request_type_t type; struct agent *agent; DBusMessage *msg; DBusPendingCall *call; void *cb; void *user_data; GDestroyNotify destroy; }; static DBusConnection *connection = NULL; static void agent_release(struct agent *agent) { DBusMessage *message; DBG("Releasing agent %s, %s", agent->name, agent->path); if (agent->request) agent_cancel(agent); message = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "Release"); if (message == NULL) { error("Couldn't allocate D-Bus message"); return; } g_dbus_send_message(connection, message); } static int send_cancel_request(struct agent_request *req) { DBusMessage *message; DBG("Sending Cancel request to %s, %s", req->agent->name, req->agent->path); message = dbus_message_new_method_call(req->agent->name, req->agent->path, "org.bluez.Agent", "Cancel"); if (message == NULL) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } g_dbus_send_message(connection, message); return 0; } static void agent_request_free(struct agent_request *req, gboolean destroy) { if (req->msg) dbus_message_unref(req->msg); if (req->call) dbus_pending_call_unref(req->call); if (req->agent && req->agent->request) req->agent->request = NULL; if (destroy && req->destroy) req->destroy(req->user_data); g_free(req); } static void agent_exited(DBusConnection *conn, void *user_data) { struct agent *agent = user_data; DBG("Agent exited without calling Unregister"); agent->exited = TRUE; agent_free(agent); } void agent_free(struct agent *agent) { if (!agent) return; if (agent->remove_cb) agent->remove_cb(agent, agent->remove_cb_data); if (agent->request) { DBusError err; agent_pincode_cb pincode_cb; agent_passkey_cb passkey_cb; agent_cb cb; dbus_error_init(&err); dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled"); switch (agent->request->type) { case AGENT_REQUEST_PINCODE: pincode_cb = agent->request->cb; pincode_cb(agent, &err, NULL, agent->request->user_data); break; case AGENT_REQUEST_PASSKEY: passkey_cb = agent->request->cb; passkey_cb(agent, &err, 0, agent->request->user_data); break; default: cb = agent->request->cb; cb(agent, &err, agent->request->user_data); } dbus_error_free(&err); agent_cancel(agent); } if (!agent->exited) { g_dbus_remove_watch(connection, agent->listener_id); agent_release(agent); } g_free(agent->name); g_free(agent->path); g_free(agent); } struct agent *agent_create(struct btd_adapter *adapter, const char *name, const char *path, uint8_t capability, agent_remove_cb cb, void *remove_cb_data) { struct agent *agent; agent = g_new0(struct agent, 1); agent->adapter = adapter; agent->name = g_strdup(name); agent->path = g_strdup(path); agent->capability = capability; agent->remove_cb = cb; agent->remove_cb_data = remove_cb_data; agent->listener_id = g_dbus_add_disconnect_watch(connection, name, agent_exited, agent, NULL); return agent; } static struct agent_request *agent_request_new(struct agent *agent, agent_request_type_t type, void *cb, void *user_data, GDestroyNotify destroy) { struct agent_request *req; req = g_new0(struct agent_request, 1); req->agent = agent; req->type = type; req->cb = cb; req->user_data = user_data; req->destroy = destroy; return req; } int agent_cancel(struct agent *agent) { if (!agent->request) return -EINVAL; if (agent->request->call) dbus_pending_call_cancel(agent->request->call); if (!agent->exited) send_cancel_request(agent->request); agent_request_free(agent->request, TRUE); agent->request = NULL; return 0; } static void simple_agent_reply(DBusPendingCall *call, void *user_data) { struct agent_request *req = user_data; struct agent *agent = req->agent; DBusMessage *message; DBusError err; agent_cb cb = req->cb; /* steal_reply will always return non-NULL since the callback * is only called after a reply has been received */ message = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, message)) { error("Agent replied with an error: %s, %s", err.name, err.message); cb(agent, &err, req->user_data); if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { agent_cancel(agent); dbus_message_unref(message); dbus_error_free(&err); return; } dbus_error_free(&err); goto done; } if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) { error("Wrong reply signature: %s", err.message); cb(agent, &err, req->user_data); dbus_error_free(&err); goto done; } cb(agent, NULL, req->user_data); done: dbus_message_unref(message); agent->request = NULL; agent_request_free(req, TRUE); } static int agent_call_authorize(struct agent_request *req, const char *device_path, const char *uuid) { struct agent *agent = req->agent; req->msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "Authorize"); if (!req->msg) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, req->msg, &req->call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); return -EIO; } dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); return 0; } int agent_authorize(struct agent *agent, const char *path, const char *uuid, agent_cb cb, void *user_data, GDestroyNotify destroy) { struct agent_request *req; int err; if (agent->request) return -EBUSY; req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb, user_data, destroy); err = agent_call_authorize(req, path, uuid); if (err < 0) { agent_request_free(req, FALSE); return -ENOMEM; } agent->request = req; DBG("authorize request was sent for %s", path); return 0; } static void pincode_reply(DBusPendingCall *call, void *user_data) { struct agent_request *req = user_data; struct agent *agent = req->agent; struct btd_adapter *adapter = agent->adapter; agent_pincode_cb cb = req->cb; DBusMessage *message; DBusError err; bdaddr_t sba; size_t len; char *pin; adapter_get_address(adapter, &sba); /* steal_reply will always return non-NULL since the callback * is only called after a reply has been received */ message = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, message)) { error("Agent %s replied with an error: %s, %s", agent->path, err.name, err.message); cb(agent, &err, NULL, req->user_data); dbus_error_free(&err); goto done; } if (!dbus_message_get_args(message, &err, DBUS_TYPE_STRING, &pin, DBUS_TYPE_INVALID)) { error("Wrong passkey reply signature: %s", err.message); cb(agent, &err, NULL, req->user_data); dbus_error_free(&err); goto done; } len = strlen(pin); if (len > 16 || len < 1) { error("Invalid PIN length (%zu) from agent", len); dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs", "Invalid passkey length"); cb(agent, &err, NULL, req->user_data); dbus_error_free(&err); goto done; } cb(agent, NULL, pin, req->user_data); done: if (message) dbus_message_unref(message); dbus_pending_call_cancel(req->call); agent->request = NULL; agent_request_free(req, TRUE); } static int pincode_request_new(struct agent_request *req, const char *device_path, dbus_bool_t secure) { struct agent *agent = req->agent; /* TODO: Add a new method or a new param to Agent interface to request secure pin. */ req->msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "RequestPinCode"); if (req->msg == NULL) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, req->msg, &req->call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); return -EIO; } dbus_pending_call_set_notify(req->call, pincode_reply, req, NULL); return 0; } int agent_request_pincode(struct agent *agent, struct btd_device *device, agent_pincode_cb cb, gboolean secure, void *user_data, GDestroyNotify destroy) { struct agent_request *req; const gchar *dev_path = device_get_path(device); int err; if (agent->request) return -EBUSY; req = agent_request_new(agent, AGENT_REQUEST_PINCODE, cb, user_data, destroy); err = pincode_request_new(req, dev_path, secure); if (err < 0) goto failed; agent->request = req; return 0; failed: agent_request_free(req, FALSE); return err; } static int confirm_mode_change_request_new(struct agent_request *req, const char *mode) { struct agent *agent = req->agent; req->msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "ConfirmModeChange"); if (req->msg == NULL) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_append_args(req->msg, DBUS_TYPE_STRING, &mode, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, req->msg, &req->call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); return -EIO; } dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); return 0; } int agent_confirm_mode_change(struct agent *agent, const char *new_mode, agent_cb cb, void *user_data, GDestroyNotify destroy) { struct agent_request *req; int err; if (agent->request) return -EBUSY; DBG("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s", agent->name, agent->path, new_mode); req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE, cb, user_data, destroy); err = confirm_mode_change_request_new(req, new_mode); if (err < 0) goto failed; agent->request = req; return 0; failed: agent_request_free(req, FALSE); return err; } static void passkey_reply(DBusPendingCall *call, void *user_data) { struct agent_request *req = user_data; struct agent *agent = req->agent; agent_passkey_cb cb = req->cb; DBusMessage *message; DBusError err; uint32_t passkey; /* steal_reply will always return non-NULL since the callback * is only called after a reply has been received */ message = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, message)) { error("Agent replied with an error: %s, %s", err.name, err.message); cb(agent, &err, 0, req->user_data); dbus_error_free(&err); goto done; } if (!dbus_message_get_args(message, &err, DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_INVALID)) { error("Wrong passkey reply signature: %s", err.message); cb(agent, &err, 0, req->user_data); dbus_error_free(&err); goto done; } cb(agent, NULL, passkey, req->user_data); done: if (message) dbus_message_unref(message); dbus_pending_call_cancel(req->call); agent->request = NULL; agent_request_free(req, TRUE); } static int passkey_request_new(struct agent_request *req, const char *device_path) { struct agent *agent = req->agent; req->msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "RequestPasskey"); if (req->msg == NULL) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, req->msg, &req->call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); return -EIO; } dbus_pending_call_set_notify(req->call, passkey_reply, req, NULL); return 0; } int agent_request_passkey(struct agent *agent, struct btd_device *device, agent_passkey_cb cb, void *user_data, GDestroyNotify destroy) { struct agent_request *req; const gchar *dev_path = device_get_path(device); int err; if (agent->request) return -EBUSY; DBG("Calling Agent.RequestPasskey: name=%s, path=%s", agent->name, agent->path); req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb, user_data, destroy); err = passkey_request_new(req, dev_path); if (err < 0) goto failed; agent->request = req; return 0; failed: agent_request_free(req, FALSE); return err; } static int confirmation_request_new(struct agent_request *req, const char *device_path, uint32_t passkey) { struct agent *agent = req->agent; req->msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "RequestConfirmation"); if (req->msg == NULL) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, req->msg, &req->call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); return -EIO; } dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL); return 0; } int agent_request_confirmation(struct agent *agent, struct btd_device *device, uint32_t passkey, agent_cb cb, void *user_data, GDestroyNotify destroy) { struct agent_request *req; const gchar *dev_path = device_get_path(device); int err; if (agent->request) return -EBUSY; DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u", agent->name, agent->path, passkey); req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb, user_data, destroy); err = confirmation_request_new(req, dev_path, passkey); if (err < 0) goto failed; agent->request = req; return 0; failed: agent_request_free(req, FALSE); return err; } int agent_display_passkey(struct agent *agent, struct btd_device *device, uint32_t passkey) { DBusMessage *message; const gchar *dev_path = device_get_path(device); message = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "DisplayPasskey"); if (!message) { error("Couldn't allocate D-Bus message"); return -1; } dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_INVALID); if (!g_dbus_send_message(connection, message)) { error("D-Bus send failed"); return -1; } return 0; } static void display_pincode_reply(DBusPendingCall *call, void *user_data) { struct agent_request *req = user_data; struct agent *agent = req->agent; DBusMessage *message; DBusError err; agent_cb cb = req->cb; /* clear agent->request early; our callback will likely try * another request */ agent->request = NULL; /* steal_reply will always return non-NULL since the callback * is only called after a reply has been received */ message = dbus_pending_call_steal_reply(call); dbus_error_init(&err); if (dbus_set_error_from_message(&err, message)) { error("Agent replied with an error: %s, %s", err.name, err.message); cb(agent, &err, req->user_data); if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) { agent_cancel(agent); dbus_message_unref(message); dbus_error_free(&err); return; } dbus_error_free(&err); goto done; } if (!dbus_message_get_args(message, &err, DBUS_TYPE_INVALID)) { error("Wrong reply signature: %s", err.message); cb(agent, &err, req->user_data); dbus_error_free(&err); goto done; } cb(agent, NULL, req->user_data); done: dbus_message_unref(message); agent_request_free(req, TRUE); } static int display_pincode_request_new(struct agent_request *req, const char *device_path, const char *pincode) { struct agent *agent = req->agent; req->msg = dbus_message_new_method_call(agent->name, agent->path, "org.bluez.Agent", "DisplayPinCode"); if (req->msg == NULL) { error("Couldn't allocate D-Bus message"); return -ENOMEM; } dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path, DBUS_TYPE_STRING, &pincode, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, req->msg, &req->call, REQUEST_TIMEOUT) == FALSE) { error("D-Bus send failed"); return -EIO; } dbus_pending_call_set_notify(req->call, display_pincode_reply, req, NULL); return 0; } int agent_display_pincode(struct agent *agent, struct btd_device *device, const char *pincode, agent_cb cb, void *user_data, GDestroyNotify destroy) { struct agent_request *req; const gchar *dev_path = device_get_path(device); int err; if (agent->request) return -EBUSY; DBG("Calling Agent.DisplayPinCode: name=%s, path=%s, pincode=%s", agent->name, agent->path, pincode); req = agent_request_new(agent, AGENT_REQUEST_DISPLAY_PINCODE, cb, user_data, destroy); err = display_pincode_request_new(req, dev_path, pincode); if (err < 0) goto failed; agent->request = req; return 0; failed: agent_request_free(req, FALSE); return err; } uint8_t agent_get_io_capability(struct agent *agent) { return agent->capability; } gboolean agent_matches(struct agent *agent, const char *name, const char *path) { if (g_str_equal(agent->name, name) && g_str_equal(agent->path, path)) return TRUE; return FALSE; } gboolean agent_is_busy(struct agent *agent, void *user_data) { if (!agent->request) return FALSE; if (user_data && user_data != agent->request->user_data) return FALSE; return TRUE; } void agent_exit(void) { dbus_connection_unref(connection); connection = NULL; } void agent_init(void) { connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL); } bluez-4.101/src/storage.c0000644000000000000000000007315011766125764012153 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "textfile.h" #include "glib-helper.h" #include "storage.h" struct match { GSList *keys; char *pattern; }; static inline int create_filename(char *buf, size_t size, const bdaddr_t *bdaddr, const char *name) { char addr[18]; ba2str(bdaddr, addr); return create_name(buf, size, STORAGEDIR, addr, name); } int read_device_alias(const char *src, const char *dst, char *alias, size_t size) { char filename[PATH_MAX + 1], *tmp; int err; create_name(filename, PATH_MAX, STORAGEDIR, src, "aliases"); tmp = textfile_get(filename, dst); if (!tmp) return -ENXIO; err = snprintf(alias, size, "%s", tmp); free(tmp); return err < 0 ? -EIO : 0; } int write_device_alias(const char *src, const char *dst, const char *alias) { char filename[PATH_MAX + 1]; create_name(filename, PATH_MAX, STORAGEDIR, src, "aliases"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); return textfile_put(filename, dst, alias); } int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout) { char filename[PATH_MAX + 1], str[32]; snprintf(str, sizeof(str), "%d", timeout); create_filename(filename, PATH_MAX, bdaddr, "config"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); return textfile_put(filename, "discovto", str); } int read_discoverable_timeout(const char *src, int *timeout) { char filename[PATH_MAX + 1], *str; create_name(filename, PATH_MAX, STORAGEDIR, src, "config"); str = textfile_get(filename, "discovto"); if (!str) return -ENOENT; if (sscanf(str, "%d", timeout) != 1) { free(str); return -ENOENT; } free(str); return 0; } int write_pairable_timeout(bdaddr_t *bdaddr, int timeout) { char filename[PATH_MAX + 1], str[32]; snprintf(str, sizeof(str), "%d", timeout); create_filename(filename, PATH_MAX, bdaddr, "config"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); return textfile_put(filename, "pairto", str); } int read_pairable_timeout(const char *src, int *timeout) { char filename[PATH_MAX + 1], *str; create_name(filename, PATH_MAX, STORAGEDIR, src, "config"); str = textfile_get(filename, "pairto"); if (!str) return -ENOENT; if (sscanf(str, "%d", timeout) != 1) { free(str); return -ENOENT; } free(str); return 0; } int write_device_mode(bdaddr_t *bdaddr, const char *mode) { char filename[PATH_MAX + 1]; create_filename(filename, PATH_MAX, bdaddr, "config"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (strcmp(mode, "off") != 0) textfile_put(filename, "onmode", mode); return textfile_put(filename, "mode", mode); } int read_device_mode(const char *src, char *mode, int length) { char filename[PATH_MAX + 1], *str; create_name(filename, PATH_MAX, STORAGEDIR, src, "config"); str = textfile_get(filename, "mode"); if (!str) return -ENOENT; strncpy(mode, str, length); mode[length - 1] = '\0'; free(str); return 0; } int read_on_mode(const char *src, char *mode, int length) { char filename[PATH_MAX + 1], *str; create_name(filename, PATH_MAX, STORAGEDIR, src, "config"); str = textfile_get(filename, "onmode"); if (!str) return -ENOENT; strncpy(mode, str, length); mode[length - 1] = '\0'; free(str); return 0; } int write_local_name(bdaddr_t *bdaddr, const char *name) { char filename[PATH_MAX + 1], str[249]; int i; memset(str, 0, sizeof(str)); for (i = 0; i < 248 && name[i]; i++) if ((unsigned char) name[i] < 32 || name[i] == 127) str[i] = '.'; else str[i] = name[i]; create_filename(filename, PATH_MAX, bdaddr, "config"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); return textfile_put(filename, "name", str); } int read_local_name(bdaddr_t *bdaddr, char *name) { char filename[PATH_MAX + 1], *str; int len; create_filename(filename, PATH_MAX, bdaddr, "config"); str = textfile_get(filename, "name"); if (!str) return -ENOENT; len = strlen(str); if (len > HCI_MAX_NAME_LENGTH) str[HCI_MAX_NAME_LENGTH] = '\0'; strcpy(name, str); free(str); return 0; } int write_local_class(bdaddr_t *bdaddr, uint8_t *class) { char filename[PATH_MAX + 1], str[9]; sprintf(str, "0x%2.2x%2.2x%2.2x", class[2], class[1], class[0]); create_filename(filename, PATH_MAX, bdaddr, "config"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); return textfile_put(filename, "class", str); } int read_local_class(bdaddr_t *bdaddr, uint8_t *class) { char filename[PATH_MAX + 1], tmp[3], *str; int i; create_filename(filename, PATH_MAX, bdaddr, "config"); str = textfile_get(filename, "class"); if (!str) return -ENOENT; memset(tmp, 0, sizeof(tmp)); for (i = 0; i < 3; i++) { memcpy(tmp, str + (i * 2) + 2, 2); class[2 - i] = (uint8_t) strtol(tmp, NULL, 16); } free(str); return 0; } int read_remote_appearance(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint16_t *appearance) { char filename[PATH_MAX + 1], key[20], *str; create_filename(filename, PATH_MAX, local, "appearances"); ba2str(peer, key); sprintf(&key[17], "#%hhu", bdaddr_type); str = textfile_get(filename, key); if (!str) return -ENOENT; if (sscanf(str, "%hx", appearance) != 1) { free(str); return -ENOENT; } free(str); return 0; } int write_remote_appearance(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint16_t appearance) { char filename[PATH_MAX + 1], key[20], str[7]; create_filename(filename, PATH_MAX, local, "appearances"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, key); sprintf(&key[17], "#%hhu", bdaddr_type); sprintf(str, "0x%4.4x", appearance); return textfile_put(filename, key, str); } int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class) { char filename[PATH_MAX + 1], addr[18], str[9]; create_filename(filename, PATH_MAX, local, "classes"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, addr); sprintf(str, "0x%6.6x", class); return textfile_put(filename, addr, str); } int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class) { char filename[PATH_MAX + 1], addr[18], *str; create_filename(filename, PATH_MAX, local, "classes"); ba2str(peer, addr); str = textfile_get(filename, addr); if (!str) return -ENOENT; if (sscanf(str, "%x", class) != 1) { free(str); return -ENOENT; } free(str); return 0; } int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name) { char filename[PATH_MAX + 1], addr[18], str[HCI_MAX_NAME_LENGTH + 1]; int i; memset(str, 0, sizeof(str)); for (i = 0; i < HCI_MAX_NAME_LENGTH && name[i]; i++) if ((unsigned char) name[i] < 32 || name[i] == 127) str[i] = '.'; else str[i] = name[i]; create_filename(filename, PATH_MAX, local, "names"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, addr); return textfile_put(filename, addr, str); } int read_device_name(const char *src, const char *dst, char *name) { char filename[PATH_MAX + 1], *str; int len; create_name(filename, PATH_MAX, STORAGEDIR, src, "names"); str = textfile_get(filename, dst); if (!str) return -ENOENT; len = strlen(str); if (len > HCI_MAX_NAME_LENGTH) str[HCI_MAX_NAME_LENGTH] = '\0'; strcpy(name, str); free(str); return 0; } int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data, uint8_t data_len) { char filename[PATH_MAX + 1], addr[18], str[481]; int i; memset(str, 0, sizeof(str)); for (i = 0; i < data_len; i++) sprintf(str + (i * 2), "%2.2X", data[i]); create_filename(filename, PATH_MAX, local, "eir"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, addr); return textfile_put(filename, addr, str); } int read_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data) { char filename[PATH_MAX + 1], addr[18], *str; int i; create_filename(filename, PATH_MAX, local, "eir"); ba2str(peer, addr); str = textfile_get(filename, addr); if (!str) return -ENOENT; if (!data) { free(str); return 0; } if (strlen(str) < 480) { free(str); return -EIO; } for (i = 0; i < HCI_MAX_EIR_LENGTH; i++) sscanf(str + (i * 2), "%02hhX", &data[i]); free(str); return 0; } int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer, uint8_t lmp_ver, uint16_t lmp_subver) { char filename[PATH_MAX + 1], addr[18], str[16]; memset(str, 0, sizeof(str)); sprintf(str, "%d %d %d", manufacturer, lmp_ver, lmp_subver); create_filename(filename, PATH_MAX, local, "manufacturers"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, addr); return textfile_put(filename, addr, str); } int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *page1, unsigned char *page2) { char filename[PATH_MAX + 1], addr[18]; char str[] = "0000000000000000 0000000000000000"; char *old_value; int i; ba2str(peer, addr); create_filename(filename, PATH_MAX, local, "features"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); old_value = textfile_get(filename, addr); if (page1) for (i = 0; i < 8; i++) sprintf(str + (i * 2), "%2.2X", page1[i]); else if (old_value && strlen(old_value) >= 16) strncpy(str, old_value, 16); if (page2) for (i = 0; i < 8; i++) sprintf(str + 17 + (i * 2), "%2.2X", page2[i]); else if (old_value && strlen(old_value) >= 33) strncpy(str + 17, old_value + 17, 16); free(old_value); return textfile_put(filename, addr, str); } static int decode_bytes(const char *str, unsigned char *bytes, size_t len) { unsigned int i; for (i = 0; i < len; i++) { if (sscanf(str + (i * 2), "%02hhX", &bytes[i]) != 1) return -EINVAL; } return 0; } int read_remote_features(bdaddr_t *local, bdaddr_t *peer, unsigned char *page1, unsigned char *page2) { char filename[PATH_MAX + 1], addr[18], *str; size_t len; int err; if (page1 == NULL && page2 == NULL) return -EINVAL; create_filename(filename, PATH_MAX, local, "features"); ba2str(peer, addr); str = textfile_get(filename, addr); if (!str) return -ENOENT; len = strlen(str); err = -ENOENT; if (page1 && len >= 16) err = decode_bytes(str, page1, 8); if (page2 && len >= 33) err = decode_bytes(str + 17, page2, 8); free(str); return err; } int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm) { char filename[PATH_MAX + 1], addr[18], str[24]; memset(str, 0, sizeof(str)); strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm); create_filename(filename, PATH_MAX, local, "lastseen"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, addr); return textfile_put(filename, addr, str); } int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm) { char filename[PATH_MAX + 1], addr[18], str[24]; memset(str, 0, sizeof(str)); strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm); create_filename(filename, PATH_MAX, local, "lastused"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, addr); return textfile_put(filename, addr, str); } int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length) { char filename[PATH_MAX + 1], addr[18], str[38]; int i; memset(str, 0, sizeof(str)); for (i = 0; i < 16; i++) sprintf(str + (i * 2), "%2.2X", key[i]); sprintf(str + 32, " %d %d", type, length); create_filename(filename, PATH_MAX, local, "linkkeys"); create_file(filename, S_IRUSR | S_IWUSR); ba2str(peer, addr); if (length < 0) { char *tmp = textfile_get(filename, addr); if (tmp) { if (strlen(tmp) > 34) memcpy(str + 34, tmp + 34, 3); free(tmp); } } return textfile_put(filename, addr, str); } int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type) { char filename[PATH_MAX + 1], addr[18], tmp[3], *str; int i; create_filename(filename, PATH_MAX, local, "linkkeys"); ba2str(peer, addr); str = textfile_get(filename, addr); if (!str) return -ENOENT; if (!key) { free(str); return 0; } memset(tmp, 0, sizeof(tmp)); for (i = 0; i < 16; i++) { memcpy(tmp, str + (i * 2), 2); key[i] = (uint8_t) strtol(tmp, NULL, 16); } if (type) { memcpy(tmp, str + 33, 2); *type = (uint8_t) strtol(tmp, NULL, 10); } free(str); return 0; } ssize_t read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin) { char filename[PATH_MAX + 1], addr[18], *str; ssize_t len; create_filename(filename, PATH_MAX, local, "pincodes"); ba2str(peer, addr); str = textfile_get(filename, addr); if (!str) return -ENOENT; strncpy(pin, str, 16); len = strlen(pin); free(str); return len; } static GSList *service_string_to_list(char *services) { GSList *l = NULL; char *start = services; int i, finished = 0; for (i = 0; !finished; i++) { if (services[i] == '\0') finished = 1; if (services[i] == ' ' || services[i] == '\0') { services[i] = '\0'; l = g_slist_append(l, start); start = services + i + 1; } } return l; } static char *service_list_to_string(GSList *services) { char str[1024]; int len = 0; if (!services) return g_strdup(""); memset(str, 0, sizeof(str)); while (services) { int ret; char *ident = services->data; ret = snprintf(str + len, sizeof(str) - len - 1, "%s%s", ident, services->next ? " " : ""); if (ret > 0) len += ret; services = services->next; } return g_strdup(str); } int write_trust(const char *src, const char *addr, const char *service, gboolean trust) { char filename[PATH_MAX + 1], *str; GSList *services = NULL, *match; gboolean trusted; int ret; create_name(filename, PATH_MAX, STORAGEDIR, src, "trusts"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); str = textfile_caseget(filename, addr); if (str) services = service_string_to_list(str); match = g_slist_find_custom(services, service, (GCompareFunc) strcmp); trusted = match ? TRUE : FALSE; /* If the old setting is the same as the requested one, we're done */ if (trusted == trust) { g_slist_free(services); free(str); return 0; } if (trust) services = g_slist_append(services, (void *) service); else services = g_slist_remove(services, match->data); /* Remove the entry if the last trusted service was removed */ if (!trust && !services) ret = textfile_casedel(filename, addr); else { char *new_str = service_list_to_string(services); ret = textfile_caseput(filename, addr, new_str); g_free(new_str); } g_slist_free(services); free(str); return ret; } gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service) { char filename[PATH_MAX + 1], *str; GSList *services; gboolean ret; create_filename(filename, PATH_MAX, local, "trusts"); str = textfile_caseget(filename, addr); if (!str) return FALSE; services = service_string_to_list(str); if (g_slist_find_custom(services, service, (GCompareFunc) strcmp)) ret = TRUE; else ret = FALSE; g_slist_free(services); free(str); return ret; } int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles) { char filename[PATH_MAX + 1], addr[18]; if (!profiles) return -EINVAL; create_filename(filename, PATH_MAX, src, "profiles"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(dst, addr); return textfile_put(filename, addr, profiles); } int delete_entry(bdaddr_t *src, const char *storage, const char *key) { char filename[PATH_MAX + 1]; create_filename(filename, PATH_MAX, src, storage); return textfile_del(filename, key); } int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec) { char filename[PATH_MAX + 1], key[28]; sdp_buf_t buf; int err, size, i; char *str; create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); snprintf(key, sizeof(key), "%17s#%08X", dst, rec->handle); if (sdp_gen_record_pdu(rec, &buf) < 0) return -1; size = buf.data_size; str = g_malloc0(size*2+1); for (i = 0; i < size; i++) sprintf(str + (i * 2), "%02X", buf.data[i]); err = textfile_put(filename, key, str); free(buf.data); g_free(str); return err; } sdp_record_t *record_from_string(const gchar *str) { sdp_record_t *rec; int size, i, len; uint8_t *pdata; char tmp[3]; size = strlen(str)/2; pdata = g_malloc0(size); tmp[2] = 0; for (i = 0; i < size; i++) { memcpy(tmp, str + (i * 2), 2); pdata[i] = (uint8_t) strtol(tmp, NULL, 16); } rec = sdp_extract_pdu(pdata, size, &len); g_free(pdata); return rec; } sdp_record_t *fetch_record(const gchar *src, const gchar *dst, const uint32_t handle) { char filename[PATH_MAX + 1], key[28], *str; sdp_record_t *rec; create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp"); snprintf(key, sizeof(key), "%17s#%08X", dst, handle); str = textfile_get(filename, key); if (!str) return NULL; rec = record_from_string(str); free(str); return rec; } int delete_record(const gchar *src, const gchar *dst, const uint32_t handle) { char filename[PATH_MAX + 1], key[28]; create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp"); snprintf(key, sizeof(key), "%17s#%08X", dst, handle); return textfile_del(filename, key); } struct record_list { sdp_list_t *recs; const gchar *addr; }; static void create_stored_records_from_keys(char *key, char *value, void *user_data) { struct record_list *rec_list = user_data; const gchar *addr = rec_list->addr; sdp_record_t *rec; if (strncmp(key, addr, 17)) return; rec = record_from_string(value); rec_list->recs = sdp_list_append(rec_list->recs, rec); } void delete_all_records(const bdaddr_t *src, const bdaddr_t *dst) { sdp_list_t *records, *seq; char srcaddr[18], dstaddr[18]; ba2str(src, srcaddr); ba2str(dst, dstaddr); records = read_records(src, dst); for (seq = records; seq; seq = seq->next) { sdp_record_t *rec = seq->data; delete_record(srcaddr, dstaddr, rec->handle); } if (records) sdp_list_free(records, (sdp_free_func_t) sdp_record_free); } sdp_list_t *read_records(const bdaddr_t *src, const bdaddr_t *dst) { char filename[PATH_MAX + 1]; struct record_list rec_list; char srcaddr[18], dstaddr[18]; ba2str(src, srcaddr); ba2str(dst, dstaddr); rec_list.addr = dstaddr; rec_list.recs = NULL; create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "sdp"); textfile_foreach(filename, create_stored_records_from_keys, &rec_list); return rec_list.recs; } sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid) { sdp_list_t *seq; for (seq = recs; seq; seq = seq->next) { sdp_record_t *rec = (sdp_record_t *) seq->data; sdp_list_t *svcclass = NULL; char *uuid_str; if (sdp_get_service_classes(rec, &svcclass) < 0) continue; /* Extract the uuid */ uuid_str = bt_uuid2string(svcclass->data); if (!uuid_str) continue; if (!strcasecmp(uuid_str, uuid)) { sdp_list_free(svcclass, free); free(uuid_str); return rec; } sdp_list_free(svcclass, free); free(uuid_str); } return NULL; } int store_device_id(const gchar *src, const gchar *dst, const uint16_t source, const uint16_t vendor, const uint16_t product, const uint16_t version) { char filename[PATH_MAX + 1], str[20]; create_name(filename, PATH_MAX, STORAGEDIR, src, "did"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); snprintf(str, sizeof(str), "%04X %04X %04X %04X", source, vendor, product, version); return textfile_put(filename, dst, str); } static int read_device_id_from_did(const gchar *src, const gchar *dst, uint16_t *source, uint16_t *vendor, uint16_t *product, uint16_t *version) { char filename[PATH_MAX + 1]; char *str, *vendor_str, *product_str, *version_str; create_name(filename, PATH_MAX, STORAGEDIR, src, "did"); str = textfile_get(filename, dst); if (!str) return -ENOENT; vendor_str = strchr(str, ' '); if (!vendor_str) { free(str); return -ENOENT; } *(vendor_str++) = 0; product_str = strchr(vendor_str, ' '); if (!product_str) { free(str); return -ENOENT; } *(product_str++) = 0; version_str = strchr(product_str, ' '); if (!version_str) { free(str); return -ENOENT; } *(version_str++) = 0; if (source) *source = (uint16_t) strtol(str, NULL, 16); if (vendor) *vendor = (uint16_t) strtol(vendor_str, NULL, 16); if (product) *product = (uint16_t) strtol(product_str, NULL, 16); if (version) *version = (uint16_t) strtol(version_str, NULL, 16); free(str); return 0; } int read_device_id(const gchar *srcaddr, const gchar *dstaddr, uint16_t *source, uint16_t *vendor, uint16_t *product, uint16_t *version) { uint16_t lsource, lvendor, lproduct, lversion; sdp_list_t *recs; sdp_record_t *rec; bdaddr_t src, dst; int err; err = read_device_id_from_did(srcaddr, dstaddr, &lsource, vendor, product, version); if (!err) { if (lsource == 0xffff) err = -ENOENT; return err; } str2ba(srcaddr, &src); str2ba(dstaddr, &dst); recs = read_records(&src, &dst); rec = find_record_in_list(recs, PNP_UUID); if (rec) { sdp_data_t *pdlist; pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID_SOURCE); lsource = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID); lvendor = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID); lproduct = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, SDP_ATTR_VERSION); lversion = pdlist ? pdlist->val.uint16 : 0x0000; err = 0; } sdp_list_free(recs, (sdp_free_func_t)sdp_record_free); if (err) { /* FIXME: We should try EIR data if we have it, too */ /* If we don't have the data, we don't want to go through the * above search every time. */ lsource = 0xffff; lvendor = 0x0000; lproduct = 0x0000; lversion = 0x0000; } store_device_id(srcaddr, dstaddr, lsource, lvendor, lproduct, lversion); if (err) return err; if (source) *source = lsource; if (vendor) *vendor = lvendor; if (product) *product = lproduct; if (version) *version = lversion; return 0; } int write_device_pairable(bdaddr_t *bdaddr, gboolean mode) { char filename[PATH_MAX + 1]; create_filename(filename, PATH_MAX, bdaddr, "config"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); return textfile_put(filename, "pairable", mode ? "yes" : "no"); } int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode) { char filename[PATH_MAX + 1], *str; create_filename(filename, PATH_MAX, bdaddr, "config"); str = textfile_get(filename, "pairable"); if (!str) return -ENOENT; *mode = strcmp(str, "yes") == 0 ? TRUE : FALSE; free(str); return 0; } gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote) { char filename[PATH_MAX + 1], *str, addr[18]; create_filename(filename, PATH_MAX, local, "blocked"); ba2str(remote, addr); str = textfile_caseget(filename, addr); if (!str) return FALSE; free(str); return TRUE; } int write_blocked(const bdaddr_t *local, const bdaddr_t *remote, gboolean blocked) { char filename[PATH_MAX + 1], addr[18]; create_filename(filename, PATH_MAX, local, "blocked"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(remote, addr); if (blocked == FALSE) return textfile_casedel(filename, addr); return textfile_caseput(filename, addr, ""); } int write_device_services(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, const char *services) { char filename[PATH_MAX + 1], key[20]; create_filename(filename, PATH_MAX, sba, "primaries"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(dba, key); sprintf(&key[17], "#%hhu", bdaddr_type); return textfile_put(filename, key, services); } static void filter_keys(char *key, char *value, void *data) { struct match *match = data; if (strncasecmp(key, match->pattern, strlen(match->pattern)) == 0) match->keys = g_slist_append(match->keys, g_strdup(key)); } static void delete_by_pattern(const char *filename, char *pattern) { struct match match; GSList *l; int err; memset(&match, 0, sizeof(match)); match.pattern = pattern; err = textfile_foreach(filename, filter_keys, &match); if (err < 0) goto done; for (l = match.keys; l; l = l->next) { const char *key = l->data; textfile_del(filename, key); } done: g_slist_free_full(match.keys, g_free); } int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type) { char filename[PATH_MAX + 1], key[20]; memset(key, 0, sizeof(key)); ba2str(dba, key); sprintf(&key[17], "#%hhu", bdaddr_type); /* Deleting all characteristics of a given key */ create_filename(filename, PATH_MAX, sba, "characteristics"); delete_by_pattern(filename, key); /* Deleting all attributes values of a given key */ create_filename(filename, PATH_MAX, sba, "attributes"); delete_by_pattern(filename, key); /* Deleting all CCC values of a given key */ create_filename(filename, PATH_MAX, sba, "ccc"); delete_by_pattern(filename, key); create_filename(filename, PATH_MAX, sba, "primaries"); return textfile_del(filename, key); } char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type) { char filename[PATH_MAX + 1], key[20]; create_filename(filename, PATH_MAX, sba, "primaries"); ba2str(dba, key); sprintf(&key[17], "#%hhu", bdaddr_type); return textfile_caseget(filename, key); } int write_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, uint16_t handle, const char *chars) { char filename[PATH_MAX + 1], addr[18], key[25]; create_filename(filename, PATH_MAX, sba, "characteristics"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(dba, addr); snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle); return textfile_put(filename, key, chars); } char *read_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, uint16_t handle) { char filename[PATH_MAX + 1], addr[18], key[25]; create_filename(filename, PATH_MAX, sba, "characteristics"); ba2str(dba, addr); snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle); return textfile_caseget(filename, key); } int write_device_attribute(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, uint16_t handle, const char *chars) { char filename[PATH_MAX + 1], addr[18], key[25]; create_filename(filename, PATH_MAX, sba, "attributes"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(dba, addr); snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle); return textfile_put(filename, key, chars); } int read_device_attributes(const bdaddr_t *sba, textfile_cb func, void *data) { char filename[PATH_MAX + 1]; create_filename(filename, PATH_MAX, sba, "attributes"); return textfile_foreach(filename, func, data); } int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint16_t handle, uint16_t *value) { char filename[PATH_MAX + 1], addr[18], key[25]; char *str; unsigned int config; int err = 0; create_filename(filename, PATH_MAX, local, "ccc"); ba2str(peer, addr); snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle); str = textfile_caseget(filename, key); if (str == NULL) return -ENOENT; if (sscanf(str, "%04X", &config) != 1) err = -ENOENT; else *value = config; free(str); return err; } int write_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint16_t handle, uint16_t value) { char filename[PATH_MAX + 1], addr[18], key[25], config[5]; create_filename(filename, PATH_MAX, local, "ccc"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, addr); snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle); snprintf(config, sizeof(config), "%04X", value); return textfile_put(filename, key, config); } void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer) { char filename[PATH_MAX + 1], addr[18]; ba2str(peer, addr); /* Deleting all CCC values of a given address */ create_filename(filename, PATH_MAX, local, "ccc"); delete_by_pattern(filename, addr); } int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, const char *key) { char filename[PATH_MAX + 1], addr[20]; if (!key) return -EINVAL; create_filename(filename, PATH_MAX, local, "longtermkeys"); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(peer, addr); sprintf(&addr[17], "#%hhu", bdaddr_type); return textfile_put(filename, addr, key); } gboolean has_longtermkeys(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type) { char filename[PATH_MAX + 1], key[20], *str; create_filename(filename, PATH_MAX, local, "longtermkeys"); ba2str(peer, key); sprintf(&key[17], "#%hhu", bdaddr_type); str = textfile_caseget(filename, key); if (str) { free(str); return TRUE; } return FALSE; } bluez-4.101/src/event.c0000644000000000000000000003152611766125764011631 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "log.h" #include "adapter.h" #include "manager.h" #include "device.h" #include "error.h" #include "dbus-common.h" #include "agent.h" #include "storage.h" #include "event.h" static gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst, struct btd_adapter **adapter, struct btd_device **device, gboolean create) { DBusConnection *conn = get_dbus_connection(); char peer_addr[18]; *adapter = manager_find_adapter(src); if (!*adapter) { error("Unable to find matching adapter"); return FALSE; } ba2str(dst, peer_addr); if (create) *device = adapter_get_device(conn, *adapter, peer_addr); else *device = adapter_find_device(*adapter, peer_addr); if (create && !*device) { error("Unable to get device object!"); return FALSE; } return TRUE; } /***************************************************************** * * Section reserved to HCI commands confirmation handling and low * level events(eg: device attached/dettached. * *****************************************************************/ static void pincode_cb(struct agent *agent, DBusError *derr, const char *pincode, struct btd_device *device) { struct btd_adapter *adapter = device_get_adapter(device); bdaddr_t dba; int err; device_get_address(device, &dba, NULL); if (derr) { err = btd_adapter_pincode_reply(adapter, &dba, NULL, 0); if (err < 0) goto fail; return; } err = btd_adapter_pincode_reply(adapter, &dba, pincode, pincode ? strlen(pincode) : 0); if (err < 0) goto fail; return; fail: error("Sending PIN code reply failed: %s (%d)", strerror(-err), -err); } int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, gboolean secure) { struct btd_adapter *adapter; struct btd_device *device; char pin[17]; ssize_t pinlen; gboolean display = FALSE; if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE)) return -ENODEV; memset(pin, 0, sizeof(pin)); pinlen = btd_adapter_get_pin(adapter, device, pin, &display); if (pinlen > 0 && (!secure || pinlen == 16)) { if (display && device_is_bonding(device, NULL)) return device_request_authentication(device, AUTH_TYPE_NOTIFY_PINCODE, pin, secure, pincode_cb); btd_adapter_pincode_reply(adapter, dba, pin, pinlen); return 0; } return device_request_authentication(device, AUTH_TYPE_PINCODE, NULL, secure, pincode_cb); } static int confirm_reply(struct btd_adapter *adapter, struct btd_device *device, gboolean success) { bdaddr_t bdaddr; uint8_t bdaddr_type; device_get_address(device, &bdaddr, &bdaddr_type); return btd_adapter_confirm_reply(adapter, &bdaddr, bdaddr_type, success); } static void confirm_cb(struct agent *agent, DBusError *err, void *user_data) { struct btd_device *device = user_data; struct btd_adapter *adapter = device_get_adapter(device); gboolean success = (err == NULL) ? TRUE : FALSE; confirm_reply(adapter, device, success); } static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey, void *user_data) { struct btd_device *device = user_data; struct btd_adapter *adapter = device_get_adapter(device); bdaddr_t bdaddr; uint8_t bdaddr_type; device_get_address(device, &bdaddr, &bdaddr_type); if (err) passkey = INVALID_PASSKEY; btd_adapter_passkey_reply(adapter, &bdaddr, bdaddr_type, passkey); } int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey) { struct btd_adapter *adapter; struct btd_device *device; if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE)) return -ENODEV; return device_request_authentication(device, AUTH_TYPE_CONFIRM, &passkey, FALSE, confirm_cb); } int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba) { struct btd_adapter *adapter; struct btd_device *device; if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE)) return -ENODEV; return device_request_authentication(device, AUTH_TYPE_PASSKEY, NULL, FALSE, passkey_cb); } int btd_event_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey) { struct btd_adapter *adapter; struct btd_device *device; if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE)) return -ENODEV; return device_request_authentication(device, AUTH_TYPE_NOTIFY_PASSKEY, &passkey, FALSE, NULL); } void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status) { struct btd_adapter *adapter; struct btd_device *device; gboolean create; DBG("status=%02x", status); create = status ? FALSE : TRUE; if (!get_adapter_and_device(local, peer, &adapter, &device, create)) return; if (!device) return; device_simple_pairing_complete(device, status); } static void update_lastseen(bdaddr_t *sba, bdaddr_t *dba) { time_t t; struct tm *tm; t = time(NULL); tm = gmtime(&t); write_lastseen_info(sba, dba, tm); } static void update_lastused(bdaddr_t *sba, bdaddr_t *dba) { time_t t; struct tm *tm; t = time(NULL); tm = gmtime(&t); write_lastused_info(sba, dba, tm); } void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, int8_t rssi, uint8_t confirm_name, uint8_t *data, uint8_t data_len) { struct btd_adapter *adapter; adapter = manager_find_adapter(local); if (!adapter) { error("No matching adapter found"); return; } update_lastseen(local, peer); if (data) write_remote_eir(local, peer, data, data_len); adapter_update_found_devices(adapter, peer, bdaddr_type, rssi, confirm_name, data, data_len); } void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer, gboolean legacy) { struct btd_adapter *adapter; struct remote_dev_info *dev; adapter = manager_find_adapter(local); if (!adapter) { error("No matching adapter found"); return; } dev = adapter_search_found_devices(adapter, peer); if (dev) dev->legacy = legacy; } void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class) { struct btd_adapter *adapter; struct btd_device *device; uint32_t old_class = 0; read_remote_class(local, peer, &old_class); if (old_class == class) return; write_remote_class(local, peer, class); if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) return; if (!device) return; device_set_class(device, class); } void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name) { struct btd_adapter *adapter; struct btd_device *device; struct remote_dev_info *dev_info; if (!g_utf8_validate(name, -1, NULL)) { int i; /* Assume ASCII, and replace all non-ASCII with spaces */ for (i = 0; name[i] != '\0'; i++) { if (!isascii(name[i])) name[i] = ' '; } /* Remove leading and trailing whitespace characters */ g_strstrip(name); } write_device_name(local, peer, name); if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) return; dev_info = adapter_search_found_devices(adapter, peer); if (dev_info) { g_free(dev_info->name); dev_info->name = g_strdup(name); adapter_emit_device_found(adapter, dev_info); } if (device) device_set_name(device, name); } static char *buf2str(uint8_t *data, int datalen) { char *buf; int i; buf = g_try_new0(char, (datalen * 2) + 1); if (buf == NULL) return NULL; for (i = 0; i < datalen; i++) sprintf(buf + (i * 2), "%2.2x", data[i]); return buf; } static int store_longtermkey(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, unsigned char *key, uint8_t master, uint8_t authenticated, uint8_t enc_size, uint16_t ediv, uint8_t rand[8]) { GString *newkey; char *val, *str; int err; val = buf2str(key, 16); if (val == NULL) return -ENOMEM; newkey = g_string_new(val); g_free(val); g_string_append_printf(newkey, " %d %d %d %d ", authenticated, master, enc_size, ediv); str = buf2str(rand, 8); if (str == NULL) { g_string_free(newkey, TRUE); return -ENOMEM; } newkey = g_string_append(newkey, str); g_free(str); err = write_longtermkeys(local, peer, bdaddr_type, newkey->str); g_string_free(newkey, TRUE); return err; } int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t *key, uint8_t key_type, uint8_t pin_length) { struct btd_adapter *adapter; struct btd_device *device; int ret; if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE)) return -ENODEV; DBG("storing link key of type 0x%02x", key_type); ret = write_link_key(local, peer, key, key_type, pin_length); if (ret == 0) { device_set_bonded(device, TRUE); if (device_is_temporary(device)) device_set_temporary(device, FALSE); } return ret; } int btd_event_ltk_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint8_t *key, uint8_t master, uint8_t authenticated, uint8_t enc_size, uint16_t ediv, uint8_t rand[8]) { struct btd_adapter *adapter; struct btd_device *device; int ret; if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE)) return -ENODEV; ret = store_longtermkey(local, peer, bdaddr_type, key, master, authenticated, enc_size, ediv, rand); if (ret == 0) { device_set_bonded(device, TRUE); if (device_is_temporary(device)) device_set_temporary(device, FALSE); } return ret; } void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, char *name, uint8_t *dev_class) { struct btd_adapter *adapter; struct btd_device *device; if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE)) return; update_lastused(local, peer); if (dev_class != NULL) { uint32_t class = dev_class[0] | (dev_class[1] << 8) | (dev_class[2] << 16); if (class != 0) write_remote_class(local, peer, class); } device_set_addr_type(device, bdaddr_type); adapter_add_connection(adapter, device); if (name != NULL) btd_event_remote_name(local, peer, name); } void btd_event_conn_failed(bdaddr_t *local, bdaddr_t *peer, uint8_t status) { struct btd_adapter *adapter; struct btd_device *device; DBusConnection *conn = get_dbus_connection(); DBG("status 0x%02x", status); if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) return; if (!device) return; if (device_is_bonding(device, NULL)) device_cancel_bonding(device, status); if (device_is_temporary(device)) adapter_remove_device(conn, adapter, device, TRUE); } void btd_event_disconn_complete(bdaddr_t *local, bdaddr_t *peer) { struct btd_adapter *adapter; struct btd_device *device; DBG(""); if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) return; if (!device) return; adapter_remove_connection(adapter, device); } void btd_event_device_blocked(bdaddr_t *local, bdaddr_t *peer) { struct btd_adapter *adapter; struct btd_device *device; DBusConnection *conn = get_dbus_connection(); if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) return; if (device) device_block(conn, device, TRUE); } void btd_event_device_unblocked(bdaddr_t *local, bdaddr_t *peer) { struct btd_adapter *adapter; struct btd_device *device; DBusConnection *conn = get_dbus_connection(); if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) return; if (device) device_unblock(conn, device, FALSE, TRUE); } void btd_event_device_unpaired(bdaddr_t *local, bdaddr_t *peer) { struct btd_adapter *adapter; struct btd_device *device; DBusConnection *conn = get_dbus_connection(); if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE)) return; device_set_temporary(device, TRUE); if (device_is_connected(device)) device_request_disconnect(device, NULL); else adapter_remove_device(conn, adapter, device, TRUE); } /* Section reserved to device HCI callbacks */ void btd_event_returned_link_key(bdaddr_t *local, bdaddr_t *peer) { struct btd_adapter *adapter; struct btd_device *device; if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE)) return; device_set_paired(device, TRUE); } bluez-4.101/src/plugin.c0000644000000000000000000001251511766125764012003 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "plugin.h" #include "log.h" #include "hcid.h" #include "btio.h" static GSList *plugins = NULL; struct bluetooth_plugin { void *handle; gboolean active; struct bluetooth_plugin_desc *desc; }; static gint compare_priority(gconstpointer a, gconstpointer b) { const struct bluetooth_plugin *plugin1 = a; const struct bluetooth_plugin *plugin2 = b; return plugin2->desc->priority - plugin1->desc->priority; } static gboolean add_plugin(void *handle, struct bluetooth_plugin_desc *desc) { struct bluetooth_plugin *plugin; if (desc->init == NULL) return FALSE; if (g_str_equal(desc->version, VERSION) == FALSE) { error("Version mismatch for %s", desc->name); return FALSE; } DBG("Loading %s plugin", desc->name); plugin = g_try_new0(struct bluetooth_plugin, 1); if (plugin == NULL) return FALSE; plugin->handle = handle; plugin->active = FALSE; plugin->desc = desc; __btd_enable_debug(desc->debug_start, desc->debug_stop); plugins = g_slist_insert_sorted(plugins, plugin, compare_priority); return TRUE; } static gboolean enable_plugin(const char *name, char **conf_disable, char **cli_enable, char **cli_disable) { if (conf_disable) { for (; *conf_disable; conf_disable++) if (g_pattern_match_simple(*conf_disable, name)) break; if (*conf_disable) { info("Excluding (conf) %s", name); return FALSE; } } if (cli_disable) { for (; *cli_disable; cli_disable++) if (g_pattern_match_simple(*cli_disable, name)) break; if (*cli_disable) { info("Excluding (cli) %s", name); return FALSE; } } if (cli_enable) { for (; *cli_enable; cli_enable++) if (g_pattern_match_simple(*cli_enable, name)) break; if (!*cli_enable) { info("Ignoring (cli) %s", name); return FALSE; } } return TRUE; } #include "builtin.h" gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable) { GSList *list; GDir *dir; const gchar *file; char **conf_disabled, **cli_disabled, **cli_enabled; unsigned int i; /* Make a call to BtIO API so its symbols got resolved before the * plugins are loaded. */ bt_io_error_quark(); if (config) conf_disabled = g_key_file_get_string_list(config, "General", "DisablePlugins", NULL, NULL); else conf_disabled = NULL; if (enable) cli_enabled = g_strsplit_set(enable, ", ", -1); else cli_enabled = NULL; if (disable) cli_disabled = g_strsplit_set(disable, ", ", -1); else cli_disabled = NULL; DBG("Loading builtin plugins"); for (i = 0; __bluetooth_builtin[i]; i++) { if (!enable_plugin(__bluetooth_builtin[i]->name, conf_disabled, cli_enabled, cli_disabled)) continue; add_plugin(NULL, __bluetooth_builtin[i]); } if (strlen(PLUGINDIR) == 0) goto start; DBG("Loading plugins %s", PLUGINDIR); dir = g_dir_open(PLUGINDIR, 0, NULL); if (!dir) goto start; while ((file = g_dir_read_name(dir)) != NULL) { struct bluetooth_plugin_desc *desc; void *handle; gchar *filename; if (g_str_has_prefix(file, "lib") == TRUE || g_str_has_suffix(file, ".so") == FALSE) continue; filename = g_build_filename(PLUGINDIR, file, NULL); handle = dlopen(filename, RTLD_NOW); if (handle == NULL) { error("Can't load plugin %s: %s", filename, dlerror()); g_free(filename); continue; } g_free(filename); desc = dlsym(handle, "bluetooth_plugin_desc"); if (desc == NULL) { error("Can't load plugin description: %s", dlerror()); dlclose(handle); continue; } if (!enable_plugin(desc->name, conf_disabled, cli_enabled, cli_disabled)) { dlclose(handle); continue; } if (add_plugin(handle, desc) == FALSE) dlclose(handle); } g_dir_close(dir); start: for (list = plugins; list; list = list->next) { struct bluetooth_plugin *plugin = list->data; if (plugin->desc->init() < 0) { error("Failed to init %s plugin", plugin->desc->name); continue; } plugin->active = TRUE; } g_strfreev(conf_disabled); g_strfreev(cli_enabled); g_strfreev(cli_disabled); return TRUE; } void plugin_cleanup(void) { GSList *list; DBG("Cleanup plugins"); for (list = plugins; list; list = list->next) { struct bluetooth_plugin *plugin = list->data; if (plugin->active == TRUE && plugin->desc->exit) plugin->desc->exit(); if (plugin->handle != NULL) dlclose(plugin->handle); g_free(plugin); } g_slist_free(plugins); } bluez-4.101/src/rfkill.c0000644000000000000000000000666011571052274011761 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include "log.h" #include "adapter.h" #include "manager.h" #include "hcid.h" enum rfkill_type { RFKILL_TYPE_ALL = 0, RFKILL_TYPE_WLAN, RFKILL_TYPE_BLUETOOTH, RFKILL_TYPE_UWB, RFKILL_TYPE_WIMAX, RFKILL_TYPE_WWAN, }; enum rfkill_operation { RFKILL_OP_ADD = 0, RFKILL_OP_DEL, RFKILL_OP_CHANGE, RFKILL_OP_CHANGE_ALL, }; struct rfkill_event { uint32_t idx; uint8_t type; uint8_t op; uint8_t soft; uint8_t hard; }; static gboolean rfkill_event(GIOChannel *chan, GIOCondition cond, gpointer data) { unsigned char buf[32]; struct rfkill_event *event = (void *) buf; struct btd_adapter *adapter; char sysname[PATH_MAX]; ssize_t len; int fd, id; if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) return FALSE; fd = g_io_channel_unix_get_fd(chan); memset(buf, 0, sizeof(buf)); len = read(fd, buf, sizeof(buf)); if (len < 0) { if (errno == EAGAIN) return TRUE; return FALSE; } if (len != sizeof(struct rfkill_event)) return TRUE; DBG("RFKILL event idx %u type %u op %u soft %u hard %u", event->idx, event->type, event->op, event->soft, event->hard); if (event->soft || event->hard) return TRUE; if (event->op != RFKILL_OP_CHANGE) return TRUE; if (event->type != RFKILL_TYPE_BLUETOOTH && event->type != RFKILL_TYPE_ALL) return TRUE; snprintf(sysname, sizeof(sysname) - 1, "/sys/class/rfkill/rfkill%u/name", event->idx); fd = open(sysname, O_RDONLY); if (fd < 0) return TRUE; memset(sysname, 0, sizeof(sysname)); if (read(fd, sysname, sizeof(sysname)) < 4) { close(fd); return TRUE; } close(fd); if (g_str_has_prefix(sysname, "hci") == FALSE) return TRUE; id = atoi(sysname + 3); if (id < 0) return TRUE; adapter = manager_find_adapter_by_id(id); if (!adapter) return TRUE; DBG("RFKILL unblock for hci%d", id); btd_adapter_restore_powered(adapter); return TRUE; } static GIOChannel *channel = NULL; void rfkill_init(void) { int fd; if (!main_opts.remember_powered) return; fd = open("/dev/rfkill", O_RDWR); if (fd < 0) { error("Failed to open RFKILL control device"); return; } channel = g_io_channel_unix_new(fd); g_io_channel_set_close_on_unref(channel, TRUE); g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR, rfkill_event, NULL); } void rfkill_exit(void) { if (!channel) return; g_io_channel_shutdown(channel, TRUE, NULL); g_io_channel_unref(channel); channel = NULL; } bluez-4.101/src/adapter.c0000644000000000000000000024640011771117441012114 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "textfile.h" #include "hcid.h" #include "sdpd.h" #include "adapter.h" #include "manager.h" #include "device.h" #include "dbus-common.h" #include "error.h" #include "glib-helper.h" #include "agent.h" #include "storage.h" #include "gattrib.h" #include "att.h" #include "gatt.h" #include "attrib-server.h" #include "eir.h" /* Flags Descriptions */ #define EIR_LIM_DISC 0x01 /* LE Limited Discoverable Mode */ #define EIR_GEN_DISC 0x02 /* LE General Discoverable Mode */ #define EIR_BREDR_UNSUP 0x04 /* BR/EDR Not Supported */ #define EIR_SIM_CONTROLLER 0x08 /* Simultaneous LE and BR/EDR to Same Device Capable (Controller) */ #define EIR_SIM_HOST 0x10 /* Simultaneous LE and BR/EDR to Same Device Capable (Host) */ #define IO_CAPABILITY_DISPLAYONLY 0x00 #define IO_CAPABILITY_DISPLAYYESNO 0x01 #define IO_CAPABILITY_KEYBOARDONLY 0x02 #define IO_CAPABILITY_NOINPUTNOOUTPUT 0x03 #define IO_CAPABILITY_KEYBOARDDISPLAY 0x04 #define IO_CAPABILITY_INVALID 0xFF #define check_address(address) bachk(address) #define OFF_TIMER 3 static DBusConnection *connection = NULL; static GSList *adapter_drivers = NULL; static GSList *ops_candidates = NULL; const struct btd_adapter_ops *adapter_ops = NULL; struct session_req { struct btd_adapter *adapter; DBusConnection *conn; /* Connection reference */ DBusMessage *msg; /* Unreplied message ref */ char *owner; /* Bus name of the owner */ guint id; /* Listener id */ uint8_t mode; /* Requested mode */ int refcount; /* Session refcount */ gboolean got_reply; /* Agent reply received */ }; struct service_auth { service_auth_cb cb; void *user_data; struct btd_device *device; struct btd_adapter *adapter; }; struct btd_adapter { uint16_t dev_id; gboolean up; char *path; /* adapter object path */ bdaddr_t bdaddr; /* adapter Bluetooth Address */ uint32_t dev_class; /* Class of Device */ char *name; /* adapter name */ gboolean allow_name_changes; /* whether the adapter name can be changed */ guint stop_discov_id; /* stop inquiry/scanning id */ uint32_t discov_timeout; /* discoverable time(sec) */ guint pairable_timeout_id; /* pairable timeout id */ uint32_t pairable_timeout; /* pairable time(sec) */ uint8_t scan_mode; /* scan mode: SCAN_DISABLED, SCAN_PAGE, * SCAN_INQUIRY */ uint8_t mode; /* off, connectable, discoverable, * limited */ uint8_t global_mode; /* last valid global mode */ struct session_req *pending_mode; int state; /* standard inq, periodic inq, name * resolving, suspended discovery */ GSList *found_devices; GSList *oor_devices; /* out of range device list */ struct agent *agent; /* For the new API */ guint auth_idle_id; /* Ongoing authorization */ GSList *connections; /* Connected devices */ GSList *devices; /* Devices structure pointers */ GSList *mode_sessions; /* Request Mode sessions */ GSList *disc_sessions; /* Discovery sessions */ guint discov_id; /* Discovery timer */ gboolean discovering; /* Discovery active */ gboolean discov_suspended; /* Discovery suspended */ guint auto_timeout_id; /* Automatic connections timeout */ sdp_list_t *services; /* Services associated to adapter */ gboolean pairable; /* pairable state */ gboolean initialized; gboolean off_requested; /* DEVDOWN ioctl was called */ gint ref; guint off_timer; GSList *powered_callbacks; GSList *pin_callbacks; GSList *loaded_drivers; }; static void dev_info_free(void *data) { struct remote_dev_info *dev = data; g_free(dev->name); g_free(dev->alias); g_slist_free_full(dev->services, g_free); g_strfreev(dev->uuids); g_free(dev); } int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major, uint8_t minor) { return adapter_ops->set_dev_class(adapter->dev_id, major, minor); } static const char *mode2str(uint8_t mode) { switch(mode) { case MODE_OFF: return "off"; case MODE_CONNECTABLE: return "connectable"; case MODE_DISCOVERABLE: return "discoverable"; default: return "unknown"; } } static uint8_t get_mode(const bdaddr_t *bdaddr, const char *mode) { if (strcasecmp("off", mode) == 0) return MODE_OFF; else if (strcasecmp("connectable", mode) == 0) return MODE_CONNECTABLE; else if (strcasecmp("discoverable", mode) == 0) return MODE_DISCOVERABLE; else if (strcasecmp("on", mode) == 0) { char onmode[14], srcaddr[18]; ba2str(bdaddr, srcaddr); if (read_on_mode(srcaddr, onmode, sizeof(onmode)) < 0) return MODE_CONNECTABLE; return get_mode(bdaddr, onmode); } else return MODE_UNKNOWN; } static struct session_req *session_ref(struct session_req *req) { req->refcount++; DBG("%p: ref=%d", req, req->refcount); return req; } static struct session_req *create_session(struct btd_adapter *adapter, DBusConnection *conn, DBusMessage *msg, uint8_t mode, GDBusWatchFunction cb) { const char *sender = dbus_message_get_sender(msg); struct session_req *req; req = g_new0(struct session_req, 1); req->adapter = adapter; req->conn = dbus_connection_ref(conn); req->msg = dbus_message_ref(msg); req->mode = mode; if (cb == NULL) return session_ref(req); req->owner = g_strdup(sender); req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req, NULL); info("%s session %p with %s activated", req->mode ? "Mode" : "Discovery", req, sender); return session_ref(req); } static int adapter_set_mode(struct btd_adapter *adapter, uint8_t mode) { int err; if (mode == MODE_CONNECTABLE) err = adapter_ops->set_discoverable(adapter->dev_id, FALSE, 0); else err = adapter_ops->set_discoverable(adapter->dev_id, TRUE, adapter->discov_timeout); return err; } static struct session_req *find_session_by_msg(GSList *list, const DBusMessage *msg) { for (; list; list = list->next) { struct session_req *req = list->data; if (req->msg == msg) return req; } return NULL; } static int set_mode(struct btd_adapter *adapter, uint8_t new_mode, DBusMessage *msg) { int err; const char *modestr; if (adapter->pending_mode != NULL) return -EALREADY; if (!adapter->up && new_mode != MODE_OFF) { err = adapter_ops->set_powered(adapter->dev_id, TRUE); if (err < 0) return err; goto done; } if (adapter->up && new_mode == MODE_OFF) { err = adapter_ops->set_powered(adapter->dev_id, FALSE); if (err < 0) return err; adapter->off_requested = TRUE; goto done; } if (new_mode == adapter->mode) return 0; err = adapter_set_mode(adapter, new_mode); if (err < 0) return err; done: modestr = mode2str(new_mode); write_device_mode(&adapter->bdaddr, modestr); DBG("%s", modestr); if (msg != NULL) { struct session_req *req; req = find_session_by_msg(adapter->mode_sessions, msg); if (req) { adapter->pending_mode = req; session_ref(req); } else /* Wait for mode change to reply */ adapter->pending_mode = create_session(adapter, connection, msg, new_mode, NULL); } else /* Nothing to reply just write the new mode */ adapter->mode = new_mode; return 0; } static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg, gboolean discoverable, void *data) { struct btd_adapter *adapter = data; uint8_t mode; int err; mode = discoverable ? MODE_DISCOVERABLE : MODE_CONNECTABLE; if (mode == adapter->mode) { adapter->global_mode = mode; return dbus_message_new_method_return(msg); } err = set_mode(adapter, mode, msg); if (err < 0) return btd_error_failed(msg, strerror(-err)); return NULL; } static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg, gboolean powered, void *data) { struct btd_adapter *adapter = data; uint8_t mode; int err; if (powered) { mode = get_mode(&adapter->bdaddr, "on"); return set_discoverable(conn, msg, mode == MODE_DISCOVERABLE, data); } mode = MODE_OFF; if (mode == adapter->mode) { adapter->global_mode = mode; return dbus_message_new_method_return(msg); } err = set_mode(adapter, mode, msg); if (err < 0) return btd_error_failed(msg, strerror(-err)); return NULL; } static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg, gboolean pairable, void *data) { struct btd_adapter *adapter = data; int err; if (adapter->scan_mode == SCAN_DISABLED) return btd_error_not_ready(msg); if (pairable == adapter->pairable) goto done; if (!(adapter->scan_mode & SCAN_INQUIRY)) goto store; err = set_mode(adapter, MODE_DISCOVERABLE, NULL); if (err < 0 && msg) return btd_error_failed(msg, strerror(-err)); store: adapter_ops->set_pairable(adapter->dev_id, pairable); done: return msg ? dbus_message_new_method_return(msg) : NULL; } static gboolean pairable_timeout_handler(void *data) { set_pairable(NULL, NULL, FALSE, data); return FALSE; } static void adapter_set_pairable_timeout(struct btd_adapter *adapter, guint interval) { if (adapter->pairable_timeout_id) { g_source_remove(adapter->pairable_timeout_id); adapter->pairable_timeout_id = 0; } if (interval == 0) return; adapter->pairable_timeout_id = g_timeout_add_seconds(interval, pairable_timeout_handler, adapter); } void btd_adapter_pairable_changed(struct btd_adapter *adapter, gboolean pairable) { adapter->pairable = pairable; write_device_pairable(&adapter->bdaddr, pairable); emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Pairable", DBUS_TYPE_BOOLEAN, &pairable); if (pairable && adapter->pairable_timeout) adapter_set_pairable_timeout(adapter, adapter->pairable_timeout); } static struct session_req *find_session(GSList *list, const char *sender) { for (; list; list = list->next) { struct session_req *req = list->data; if (g_str_equal(req->owner, sender)) return req; } return NULL; } static uint8_t get_needed_mode(struct btd_adapter *adapter, uint8_t mode) { GSList *l; if (adapter->global_mode > mode) mode = adapter->global_mode; for (l = adapter->mode_sessions; l; l = l->next) { struct session_req *req = l->data; if (req->mode > mode) mode = req->mode; } return mode; } static GSList *remove_bredr(GSList *all) { GSList *l, *le; for (l = all, le = NULL; l; l = l->next) { struct remote_dev_info *dev = l->data; if (dev->bdaddr_type == BDADDR_BREDR) { dev_info_free(dev); continue; } le = g_slist_append(le, dev); } g_slist_free(all); return le; } /* Called when a session gets removed or the adapter is stopped */ static void stop_discovery(struct btd_adapter *adapter) { adapter->found_devices = remove_bredr(adapter->found_devices); if (adapter->oor_devices) { g_slist_free(adapter->oor_devices); adapter->oor_devices = NULL; } /* Reset if suspended, otherwise remove timer (software scheduler) * or request inquiry to stop */ if (adapter->discov_suspended) { adapter->discov_suspended = FALSE; return; } if (adapter->discov_id > 0) { g_source_remove(adapter->discov_id); adapter->discov_id = 0; return; } if (adapter->up) adapter_ops->stop_discovery(adapter->dev_id); } static void session_remove(struct session_req *req) { struct btd_adapter *adapter = req->adapter; /* Ignore set_mode session */ if (req->owner == NULL) return; DBG("%s session %p with %s deactivated", req->mode ? "Mode" : "Discovery", req, req->owner); if (req->mode) { uint8_t mode; adapter->mode_sessions = g_slist_remove(adapter->mode_sessions, req); mode = get_needed_mode(adapter, adapter->global_mode); if (mode == adapter->mode) return; DBG("Switching to '%s' mode", mode2str(mode)); set_mode(adapter, mode, NULL); } else { adapter->disc_sessions = g_slist_remove(adapter->disc_sessions, req); if (adapter->disc_sessions) return; DBG("Stopping discovery"); stop_discovery(adapter); } } static void session_free(void *data) { struct session_req *req = data; if (req->id) g_dbus_remove_watch(req->conn, req->id); if (req->msg) { dbus_message_unref(req->msg); if (!req->got_reply && req->mode && req->adapter->agent) agent_cancel(req->adapter->agent); } if (req->conn) dbus_connection_unref(req->conn); g_free(req->owner); g_free(req); } static void session_owner_exit(DBusConnection *conn, void *user_data) { struct session_req *req = user_data; req->id = 0; session_remove(req); session_free(req); } static void session_unref(struct session_req *req) { req->refcount--; DBG("%p: ref=%d", req, req->refcount); if (req->refcount) return; session_remove(req); session_free(req); } static void confirm_mode_cb(struct agent *agent, DBusError *derr, void *data) { struct session_req *req = data; int err; DBusMessage *reply; req->got_reply = TRUE; if (derr && dbus_error_is_set(derr)) { reply = dbus_message_new_error(req->msg, derr->name, derr->message); g_dbus_send_message(req->conn, reply); session_unref(req); return; } err = set_mode(req->adapter, req->mode, req->msg); if (err < 0) reply = btd_error_failed(req->msg, strerror(-err)); else if (!req->adapter->pending_mode) reply = dbus_message_new_method_return(req->msg); else reply = NULL; if (reply) { /* * Send reply immediately only if there was an error changing * mode, or change is not needed. Otherwise, reply is sent in * set_mode_complete. */ g_dbus_send_message(req->conn, reply); dbus_message_unref(req->msg); req->msg = NULL; } if (!find_session(req->adapter->mode_sessions, req->owner)) session_unref(req); } static DBusMessage *set_discoverable_timeout(DBusConnection *conn, DBusMessage *msg, uint32_t timeout, void *data) { struct btd_adapter *adapter = data; const char *path; if (adapter->discov_timeout == timeout && timeout == 0) return dbus_message_new_method_return(msg); if (adapter->scan_mode & SCAN_INQUIRY) adapter_ops->set_discoverable(adapter->dev_id, TRUE, timeout); adapter->discov_timeout = timeout; write_discoverable_timeout(&adapter->bdaddr, timeout); path = dbus_message_get_path(msg); emit_property_changed(conn, path, ADAPTER_INTERFACE, "DiscoverableTimeout", DBUS_TYPE_UINT32, &timeout); return dbus_message_new_method_return(msg); } static DBusMessage *set_pairable_timeout(DBusConnection *conn, DBusMessage *msg, uint32_t timeout, void *data) { struct btd_adapter *adapter = data; const char *path; if (adapter->pairable_timeout == timeout && timeout == 0) return dbus_message_new_method_return(msg); if (adapter->pairable) adapter_set_pairable_timeout(adapter, timeout); adapter->pairable_timeout = timeout; write_pairable_timeout(&adapter->bdaddr, timeout); path = dbus_message_get_path(msg); emit_property_changed(conn, path, ADAPTER_INTERFACE, "PairableTimeout", DBUS_TYPE_UINT32, &timeout); return dbus_message_new_method_return(msg); } void btd_adapter_class_changed(struct btd_adapter *adapter, uint32_t new_class) { uint8_t class[3]; class[2] = (new_class >> 16) & 0xff; class[1] = (new_class >> 8) & 0xff; class[0] = new_class & 0xff; write_local_class(&adapter->bdaddr, class); adapter->dev_class = new_class; if (main_opts.gatt_enabled) { /* Removes service class */ class[1] = class[1] & 0x1f; attrib_gap_set(adapter, GATT_CHARAC_APPEARANCE, class, 2); } emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Class", DBUS_TYPE_UINT32, &new_class); } void adapter_name_changed(struct btd_adapter *adapter, const char *name) { if (g_strcmp0(adapter->name, name) == 0) return; g_free(adapter->name); adapter->name = g_strdup(name); if (connection) emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Name", DBUS_TYPE_STRING, &name); if (main_opts.gatt_enabled) attrib_gap_set(adapter, GATT_CHARAC_DEVICE_NAME, (const uint8_t *) name, strlen(name)); } int adapter_set_name(struct btd_adapter *adapter, const char *name) { char maxname[MAX_NAME_LENGTH + 1]; if (g_strcmp0(adapter->name, name) == 0) return 0; memset(maxname, 0, sizeof(maxname)); strncpy(maxname, name, MAX_NAME_LENGTH); if (!g_utf8_validate(maxname, -1, NULL)) { error("Name change failed: supplied name isn't valid UTF-8"); return -EINVAL; } if (adapter->up) { int err = adapter_ops->set_name(adapter->dev_id, maxname); if (err < 0) return err; } else { g_free(adapter->name); adapter->name = g_strdup(maxname); } write_local_name(&adapter->bdaddr, maxname); return 0; } static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg, const char *name, void *data) { struct btd_adapter *adapter = data; int ret; if (adapter->allow_name_changes == FALSE) return btd_error_failed(msg, strerror(EPERM)); ret = adapter_set_name(adapter, name); if (ret == -EINVAL) return btd_error_invalid_args(msg); else if (ret < 0) return btd_error_failed(msg, strerror(-ret)); return dbus_message_new_method_return(msg); } struct btd_device *adapter_find_device(struct btd_adapter *adapter, const char *dest) { struct btd_device *device; GSList *l; if (!adapter) return NULL; l = g_slist_find_custom(adapter->devices, dest, (GCompareFunc) device_address_cmp); if (!l) return NULL; device = l->data; return device; } static void adapter_update_devices(struct btd_adapter *adapter) { char **devices; int i; GSList *l; /* Devices */ devices = g_new0(char *, g_slist_length(adapter->devices) + 1); for (i = 0, l = adapter->devices; l; l = l->next, i++) { struct btd_device *dev = l->data; devices[i] = (char *) device_get_path(dev); } emit_array_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Devices", DBUS_TYPE_OBJECT_PATH, &devices, i); g_free(devices); } static void adapter_emit_uuids_updated(struct btd_adapter *adapter) { char **uuids; int i; sdp_list_t *list; if (!adapter->initialized) return; uuids = g_new0(char *, sdp_list_len(adapter->services) + 1); for (i = 0, list = adapter->services; list; list = list->next) { char *uuid; sdp_record_t *rec = list->data; uuid = bt_uuid2string(&rec->svclass); if (uuid) uuids[i++] = uuid; } emit_array_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "UUIDs", DBUS_TYPE_STRING, &uuids, i); g_strfreev(uuids); } static uint8_t get_uuid_mask(uuid_t *uuid) { if (uuid->type != SDP_UUID16) return 0; switch (uuid->value.uuid16) { case DIALUP_NET_SVCLASS_ID: case CIP_SVCLASS_ID: return 0x42; /* Telephony & Networking */ case IRMC_SYNC_SVCLASS_ID: case OBEX_OBJPUSH_SVCLASS_ID: case OBEX_FILETRANS_SVCLASS_ID: case IRMC_SYNC_CMD_SVCLASS_ID: case PBAP_PSE_SVCLASS_ID: return 0x10; /* Object Transfer */ case HEADSET_SVCLASS_ID: case HANDSFREE_SVCLASS_ID: return 0x20; /* Audio */ case CORDLESS_TELEPHONY_SVCLASS_ID: case INTERCOM_SVCLASS_ID: case FAX_SVCLASS_ID: case SAP_SVCLASS_ID: /* * Setting the telephony bit for the handsfree audio gateway * role is not required by the HFP specification, but the * Nokia 616 carkit is just plain broken! It will refuse * pairing without this bit set. */ case HANDSFREE_AGW_SVCLASS_ID: return 0x40; /* Telephony */ case AUDIO_SOURCE_SVCLASS_ID: case VIDEO_SOURCE_SVCLASS_ID: return 0x08; /* Capturing */ case AUDIO_SINK_SVCLASS_ID: case VIDEO_SINK_SVCLASS_ID: return 0x04; /* Rendering */ case PANU_SVCLASS_ID: case NAP_SVCLASS_ID: case GN_SVCLASS_ID: return 0x02; /* Networking */ default: return 0; } } static int uuid_cmp(const void *a, const void *b) { const sdp_record_t *rec = a; const uuid_t *uuid = b; return sdp_uuid_cmp(&rec->svclass, uuid); } void adapter_service_insert(struct btd_adapter *adapter, void *r) { sdp_record_t *rec = r; gboolean new_uuid; if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL) new_uuid = TRUE; else new_uuid = FALSE; adapter->services = sdp_list_insert_sorted(adapter->services, rec, record_sort); if (new_uuid) { uint8_t svc_hint = get_uuid_mask(&rec->svclass); adapter_ops->add_uuid(adapter->dev_id, &rec->svclass, svc_hint); } adapter_emit_uuids_updated(adapter); } void adapter_service_remove(struct btd_adapter *adapter, void *r) { sdp_record_t *rec = r; adapter->services = sdp_list_remove(adapter->services, rec); if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL) adapter_ops->remove_uuid(adapter->dev_id, &rec->svclass); adapter_emit_uuids_updated(adapter); } static struct btd_device *adapter_create_device(DBusConnection *conn, struct btd_adapter *adapter, const char *address, uint8_t bdaddr_type) { struct btd_device *device; const char *path; DBG("%s", address); device = device_create(conn, adapter, address, bdaddr_type); if (!device) return NULL; device_set_temporary(device, TRUE); adapter->devices = g_slist_append(adapter->devices, device); path = device_get_path(device); g_dbus_emit_signal(conn, adapter->path, ADAPTER_INTERFACE, "DeviceCreated", DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); adapter_update_devices(adapter); return device; } void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter, struct btd_device *device, gboolean remove_storage) { const gchar *dev_path = device_get_path(device); struct agent *agent; adapter->devices = g_slist_remove(adapter->devices, device); adapter->connections = g_slist_remove(adapter->connections, device); adapter_update_devices(adapter); g_dbus_emit_signal(conn, adapter->path, ADAPTER_INTERFACE, "DeviceRemoved", DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_INVALID); agent = device_get_agent(device); if (agent && device_is_authorizing(device)) agent_cancel(agent); device_remove(device, remove_storage); } struct btd_device *adapter_get_device(DBusConnection *conn, struct btd_adapter *adapter, const gchar *address) { struct btd_device *device; DBG("%s", address); if (!adapter) return NULL; device = adapter_find_device(adapter, address); if (device) return device; return adapter_create_device(conn, adapter, address, BDADDR_BREDR); } static gboolean discovery_cb(gpointer user_data) { struct btd_adapter *adapter = user_data; int err; adapter->discov_id = 0; err = adapter_ops->start_discovery(adapter->dev_id); if (err < 0) error("start_discovery: %s (%d)", strerror(-err), -err); return FALSE; } static DBusMessage *adapter_start_discovery(DBusConnection *conn, DBusMessage *msg, void *data) { struct session_req *req; struct btd_adapter *adapter = data; const char *sender = dbus_message_get_sender(msg); int err; if (!adapter->up) return btd_error_not_ready(msg); req = find_session(adapter->disc_sessions, sender); if (req) { session_ref(req); return dbus_message_new_method_return(msg); } if (adapter->disc_sessions) goto done; g_slist_free_full(adapter->found_devices, dev_info_free); adapter->found_devices = NULL; g_slist_free(adapter->oor_devices); adapter->oor_devices = NULL; if (adapter->discov_suspended) goto done; err = adapter_ops->start_discovery(adapter->dev_id); if (err < 0) return btd_error_failed(msg, strerror(-err)); done: req = create_session(adapter, conn, msg, 0, session_owner_exit); adapter->disc_sessions = g_slist_append(adapter->disc_sessions, req); return dbus_message_new_method_return(msg); } static DBusMessage *adapter_stop_discovery(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; struct session_req *req; const char *sender = dbus_message_get_sender(msg); if (!adapter->up) return btd_error_not_ready(msg); req = find_session(adapter->disc_sessions, sender); if (!req) return btd_error_failed(msg, "Invalid discovery session"); session_unref(req); info("Stopping discovery"); return dbus_message_new_method_return(msg); } static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; const char *property; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; char srcaddr[18]; gboolean value; char **devices, **uuids; int i; GSList *l; sdp_list_t *list; ba2str(&adapter->bdaddr, srcaddr); if (check_address(srcaddr) < 0) return btd_error_invalid_args(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Address */ property = srcaddr; dict_append_entry(&dict, "Address", DBUS_TYPE_STRING, &property); /* Name */ property = adapter->name ? : ""; dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &property); /* Class */ dict_append_entry(&dict, "Class", DBUS_TYPE_UINT32, &adapter->dev_class); /* Powered */ value = (adapter->up && !adapter->off_requested) ? TRUE : FALSE; dict_append_entry(&dict, "Powered", DBUS_TYPE_BOOLEAN, &value); /* Discoverable */ value = adapter->scan_mode & SCAN_INQUIRY ? TRUE : FALSE; dict_append_entry(&dict, "Discoverable", DBUS_TYPE_BOOLEAN, &value); /* Pairable */ dict_append_entry(&dict, "Pairable", DBUS_TYPE_BOOLEAN, &adapter->pairable); /* DiscoverableTimeout */ dict_append_entry(&dict, "DiscoverableTimeout", DBUS_TYPE_UINT32, &adapter->discov_timeout); /* PairableTimeout */ dict_append_entry(&dict, "PairableTimeout", DBUS_TYPE_UINT32, &adapter->pairable_timeout); /* Discovering */ dict_append_entry(&dict, "Discovering", DBUS_TYPE_BOOLEAN, &adapter->discovering); /* Devices */ devices = g_new0(char *, g_slist_length(adapter->devices) + 1); for (i = 0, l = adapter->devices; l; l = l->next, i++) { struct btd_device *dev = l->data; devices[i] = (char *) device_get_path(dev); } dict_append_array(&dict, "Devices", DBUS_TYPE_OBJECT_PATH, &devices, i); g_free(devices); /* UUIDs */ uuids = g_new0(char *, sdp_list_len(adapter->services) + 1); for (i = 0, list = adapter->services; list; list = list->next) { sdp_record_t *rec = list->data; char *uuid; uuid = bt_uuid2string(&rec->svclass); if (uuid) uuids[i++] = uuid; } dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &uuids, i); g_strfreev(uuids); dbus_message_iter_close_container(&iter, &dict); return reply; } static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter; DBusMessageIter sub; const char *property; if (!dbus_message_iter_init(msg, &iter)) return btd_error_invalid_args(msg); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return btd_error_invalid_args(msg); dbus_message_iter_recurse(&iter, &sub); if (g_str_equal("Name", property)) { const char *name; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &name); return set_name(conn, msg, name, data); } else if (g_str_equal("Powered", property)) { gboolean powered; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &powered); return set_powered(conn, msg, powered, data); } else if (g_str_equal("Discoverable", property)) { gboolean discoverable; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &discoverable); return set_discoverable(conn, msg, discoverable, data); } else if (g_str_equal("DiscoverableTimeout", property)) { uint32_t timeout; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &timeout); return set_discoverable_timeout(conn, msg, timeout, data); } else if (g_str_equal("Pairable", property)) { gboolean pairable; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &pairable); return set_pairable(conn, msg, pairable, data); } else if (g_str_equal("PairableTimeout", property)) { uint32_t timeout; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &timeout); return set_pairable_timeout(conn, msg, timeout, data); } return btd_error_invalid_args(msg); } static DBusMessage *request_session(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; struct session_req *req; const char *sender = dbus_message_get_sender(msg); uint8_t new_mode; int err; if (!adapter->agent) return btd_error_agent_not_available(msg); if (!adapter->mode_sessions) adapter->global_mode = adapter->mode; new_mode = get_mode(&adapter->bdaddr, "on"); req = find_session(adapter->mode_sessions, sender); if (req) { session_ref(req); return dbus_message_new_method_return(msg); } else { req = create_session(adapter, conn, msg, new_mode, session_owner_exit); adapter->mode_sessions = g_slist_append(adapter->mode_sessions, req); } /* No need to change mode */ if (adapter->mode >= new_mode) return dbus_message_new_method_return(msg); err = agent_confirm_mode_change(adapter->agent, mode2str(new_mode), confirm_mode_cb, req, NULL); if (err < 0) { session_unref(req); return btd_error_failed(msg, strerror(-err)); } return NULL; } static DBusMessage *release_session(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; struct session_req *req; const char *sender = dbus_message_get_sender(msg); req = find_session(adapter->mode_sessions, sender); if (!req) return btd_error_failed(msg, "Invalid Session"); session_unref(req); return dbus_message_new_method_return(msg); } static DBusMessage *list_devices(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; DBusMessage *reply; GSList *l; DBusMessageIter iter; DBusMessageIter array_iter; const gchar *dev_path; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter); for (l = adapter->devices; l; l = l->next) { struct btd_device *device = l->data; dev_path = device_get_path(device); dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_OBJECT_PATH, &dev_path); } dbus_message_iter_close_container(&iter, &array_iter); return reply; } static DBusMessage *cancel_device_creation(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; const gchar *address, *sender = dbus_message_get_sender(msg); struct btd_device *device; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID) == FALSE) return btd_error_invalid_args(msg); if (check_address(address) < 0) return btd_error_invalid_args(msg); device = adapter_find_device(adapter, address); if (!device || !device_is_creating(device, NULL)) return btd_error_does_not_exist(msg); if (!device_is_creating(device, sender)) return btd_error_not_authorized(msg); device_set_temporary(device, TRUE); if (device_is_connected(device)) { device_request_disconnect(device, msg); return NULL; } adapter_remove_device(conn, adapter, device, TRUE); return dbus_message_new_method_return(msg); } static struct btd_device *create_device_internal(DBusConnection *conn, struct btd_adapter *adapter, const char *address, int *err) { struct remote_dev_info *dev; struct btd_device *device; bdaddr_t addr; uint8_t bdaddr_type; str2ba(address, &addr); dev = adapter_search_found_devices(adapter, &addr); if (dev) bdaddr_type = dev->bdaddr_type; else bdaddr_type = BDADDR_BREDR; device = adapter_create_device(conn, adapter, address, bdaddr_type); if (!device && err) *err = -ENOMEM; return device; } static DBusMessage *create_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; struct btd_device *device; const gchar *address; DBusMessage *reply; int err; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID) == FALSE) return btd_error_invalid_args(msg); if (check_address(address) < 0) return btd_error_invalid_args(msg); if (!adapter->up) return btd_error_not_ready(msg); if (adapter_find_device(adapter, address)) return btd_error_already_exists(msg); DBG("%s", address); device = create_device_internal(conn, adapter, address, &err); if (!device) goto failed; if (device_is_bredr(device)) err = device_browse_sdp(device, conn, msg, NULL, FALSE); else err = device_browse_primary(device, conn, msg, FALSE); if (err < 0) { adapter_remove_device(conn, adapter, device, TRUE); return btd_error_failed(msg, strerror(-err)); } return NULL; failed: if (err == -ENOTCONN) { /* Device is not connectable */ const char *path = device_get_path(device); reply = dbus_message_new_method_return(msg); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); } else reply = btd_error_failed(msg, strerror(-err)); return reply; } static uint8_t parse_io_capability(const char *capability) { if (g_str_equal(capability, "")) return IO_CAPABILITY_DISPLAYYESNO; if (g_str_equal(capability, "DisplayOnly")) return IO_CAPABILITY_DISPLAYONLY; if (g_str_equal(capability, "DisplayYesNo")) return IO_CAPABILITY_DISPLAYYESNO; if (g_str_equal(capability, "KeyboardOnly")) return IO_CAPABILITY_KEYBOARDONLY; if (g_str_equal(capability, "NoInputNoOutput")) return IO_CAPABILITY_NOINPUTNOOUTPUT; if (g_str_equal(capability, "KeyboardDisplay")) return IO_CAPABILITY_KEYBOARDDISPLAY; return IO_CAPABILITY_INVALID; } static DBusMessage *create_paired_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; struct btd_device *device; const gchar *address, *agent_path, *capability, *sender; uint8_t cap; int err; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_OBJECT_PATH, &agent_path, DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID) == FALSE) return btd_error_invalid_args(msg); if (check_address(address) < 0) return btd_error_invalid_args(msg); if (!adapter->up) return btd_error_not_ready(msg); sender = dbus_message_get_sender(msg); if (adapter->agent && agent_matches(adapter->agent, sender, agent_path)) { error("Refusing adapter agent usage as device specific one"); return btd_error_invalid_args(msg); } cap = parse_io_capability(capability); if (cap == IO_CAPABILITY_INVALID) return btd_error_invalid_args(msg); device = adapter_find_device(adapter, address); if (!device) { device = create_device_internal(conn, adapter, address, &err); if (!device) return btd_error_failed(msg, strerror(-err)); } return device_create_bonding(device, conn, msg, agent_path, cap); } static gint device_path_cmp(struct btd_device *device, const gchar *path) { const gchar *dev_path = device_get_path(device); return strcasecmp(dev_path, path); } static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; struct btd_device *device; const char *path; GSList *l; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID) == FALSE) return btd_error_invalid_args(msg); l = g_slist_find_custom(adapter->devices, path, (GCompareFunc) device_path_cmp); if (!l) return btd_error_does_not_exist(msg); device = l->data; if (device_is_temporary(device) || device_is_busy(device)) return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist", "Device creation in progress"); device_set_temporary(device, TRUE); if (!device_is_connected(device)) { adapter_remove_device(conn, adapter, device, TRUE); return dbus_message_new_method_return(msg); } device_request_disconnect(device, msg); return NULL; } static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; struct btd_device *device; DBusMessage *reply; const gchar *address; GSList *l; const gchar *dev_path; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); l = g_slist_find_custom(adapter->devices, address, (GCompareFunc) device_address_cmp); if (!l) return btd_error_does_not_exist(msg); device = l->data; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dev_path = device_get_path(device); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &dev_path, DBUS_TYPE_INVALID); return reply; } static void agent_removed(struct agent *agent, struct btd_adapter *adapter) { adapter_ops->set_io_capability(adapter->dev_id, IO_CAPABILITY_NOINPUTNOOUTPUT); adapter->agent = NULL; } static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg, void *data) { const char *path, *name, *capability; struct btd_adapter *adapter = data; uint8_t cap; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID)) return NULL; if (adapter->agent) return btd_error_already_exists(msg); cap = parse_io_capability(capability); if (cap == IO_CAPABILITY_INVALID) return btd_error_invalid_args(msg); name = dbus_message_get_sender(msg); adapter->agent = agent_create(adapter, name, path, cap, (agent_remove_cb) agent_removed, adapter); DBG("Agent registered for hci%d at %s:%s", adapter->dev_id, name, path); adapter_ops->set_io_capability(adapter->dev_id, cap); return dbus_message_new_method_return(msg); } static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg, void *data) { const char *path, *name; struct btd_adapter *adapter = data; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return NULL; name = dbus_message_get_sender(msg); if (!adapter->agent || !agent_matches(adapter->agent, name, path)) return btd_error_does_not_exist(msg); agent_free(adapter->agent); adapter->agent = NULL; return dbus_message_new_method_return(msg); } static const GDBusMethodTable adapter_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), get_properties) }, { GDBUS_ASYNC_METHOD("SetProperty", GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL, set_property) }, { GDBUS_ASYNC_METHOD("RequestSession", NULL, NULL, request_session) }, { GDBUS_METHOD("ReleaseSession", NULL, NULL, release_session) }, { GDBUS_METHOD("StartDiscovery", NULL, NULL, adapter_start_discovery) }, { GDBUS_ASYNC_METHOD("StopDiscovery", NULL, NULL, adapter_stop_discovery) }, { GDBUS_DEPRECATED_METHOD("ListDevices", NULL, GDBUS_ARGS({ "devices", "ao" }), list_devices) }, { GDBUS_ASYNC_METHOD("CreateDevice", GDBUS_ARGS({ "address", "s" }), GDBUS_ARGS({ "device", "o" }), create_device) }, { GDBUS_ASYNC_METHOD("CreatePairedDevice", GDBUS_ARGS({ "address", "s" }, { "agent", "o" }, { "capability", "s" }), GDBUS_ARGS({ "device", "o" }), create_paired_device) }, { GDBUS_ASYNC_METHOD("CancelDeviceCreation", GDBUS_ARGS({ "address", "s" }), NULL, cancel_device_creation) }, { GDBUS_ASYNC_METHOD("RemoveDevice", GDBUS_ARGS({ "device", "o" }), NULL, remove_device) }, { GDBUS_METHOD("FindDevice", GDBUS_ARGS({ "address", "s" }), GDBUS_ARGS({ "device", "o" }), find_device) }, { GDBUS_METHOD("RegisterAgent", GDBUS_ARGS({ "agent", "o" }, { "capability", "s" }), NULL, register_agent) }, { GDBUS_METHOD("UnregisterAgent", GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) }, { } }; static const GDBusSignalTable adapter_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { GDBUS_SIGNAL("DeviceCreated", GDBUS_ARGS({ "device", "o" })) }, { GDBUS_SIGNAL("DeviceRemoved", GDBUS_ARGS({ "device", "o" })) }, { GDBUS_SIGNAL("DeviceFound", GDBUS_ARGS({ "address", "s" }, { "values", "a{sv}" })) }, { GDBUS_SIGNAL("DeviceDisappeared", GDBUS_ARGS({ "address", "s" })) }, { } }; static void create_stored_device_from_profiles(char *key, char *value, void *user_data) { struct btd_adapter *adapter = user_data; GSList *list, *uuids = bt_string2list(value); struct btd_device *device; if (g_slist_find_custom(adapter->devices, key, (GCompareFunc) device_address_cmp)) return; device = device_create(connection, adapter, key, BDADDR_BREDR); if (!device) return; device_set_temporary(device, FALSE); adapter->devices = g_slist_append(adapter->devices, device); list = device_services_from_record(device, uuids); if (list) device_register_services(connection, device, list, ATT_PSM); device_probe_drivers(device, uuids); g_slist_free_full(uuids, g_free); } struct adapter_keys { struct btd_adapter *adapter; GSList *keys; }; static int str2buf(const char *str, uint8_t *buf, size_t blen) { int i, dlen; if (str == NULL) return -EINVAL; memset(buf, 0, blen); dlen = MIN((strlen(str) / 2), blen); for (i = 0; i < dlen; i++) sscanf(str + (i * 2), "%02hhX", &buf[i]); return 0; } static struct link_key_info *get_key_info(const char *addr, const char *value) { struct link_key_info *info; char tmp[3]; long int l; if (strlen(value) < 36) { error("Unexpectedly short (%zu) link key line", strlen(value)); return NULL; } info = g_new0(struct link_key_info, 1); str2ba(addr, &info->bdaddr); str2buf(value, info->key, sizeof(info->key)); memcpy(tmp, value + 33, 2); info->type = (uint8_t) strtol(tmp, NULL, 10); memcpy(tmp, value + 35, 2); l = strtol(tmp, NULL, 10); if (l < 0) l = 0; info->pin_len = l; return info; } static struct smp_ltk_info *get_ltk_info(const char *addr, uint8_t bdaddr_type, const char *value) { struct smp_ltk_info *ltk; char *ptr; int i, ret; if (strlen(value) < 60) { error("Unexpectedly short (%zu) LTK", strlen(value)); return NULL; } ltk = g_new0(struct smp_ltk_info, 1); str2ba(addr, <k->bdaddr); ltk->bdaddr_type = bdaddr_type; str2buf(value, ltk->val, sizeof(ltk->val)); ptr = (char *) value + 2 * sizeof(ltk->val) + 1; ret = sscanf(ptr, " %hhd %hhd %hhd %hd %n", <k->authenticated, <k->master, <k->enc_size, <k->ediv, &i); if (ret < 2) { g_free(ltk); return NULL; } ptr += i; str2buf(ptr, ltk->rand, sizeof(ltk->rand)); return ltk; } static void create_stored_device_from_linkkeys(char *key, char *value, void *user_data) { struct adapter_keys *keys = user_data; struct btd_adapter *adapter = keys->adapter; struct btd_device *device; struct link_key_info *info; info = get_key_info(key, value); if (info) keys->keys = g_slist_append(keys->keys, info); if (g_slist_find_custom(adapter->devices, key, (GCompareFunc) device_address_cmp)) return; device = device_create(connection, adapter, key, BDADDR_BREDR); if (device) { device_set_temporary(device, FALSE); adapter->devices = g_slist_append(adapter->devices, device); } } static void create_stored_device_from_ltks(char *key, char *value, void *user_data) { struct adapter_keys *keys = user_data; struct btd_adapter *adapter = keys->adapter; struct btd_device *device; struct smp_ltk_info *info; char address[18], srcaddr[18]; uint8_t bdaddr_type; bdaddr_t src; if (sscanf(key, "%17s#%hhu", address, &bdaddr_type) < 2) return; info = get_ltk_info(address, bdaddr_type, value); if (info == NULL) return; keys->keys = g_slist_append(keys->keys, info); if (g_slist_find_custom(adapter->devices, address, (GCompareFunc) device_address_cmp)) return; adapter_get_address(adapter, &src); ba2str(&src, srcaddr); if (g_strcmp0(srcaddr, address) == 0) return; device = device_create(connection, adapter, address, bdaddr_type); if (device) { device_set_temporary(device, FALSE); adapter->devices = g_slist_append(adapter->devices, device); } } static void create_stored_device_from_blocked(char *key, char *value, void *user_data) { struct btd_adapter *adapter = user_data; struct btd_device *device; if (g_slist_find_custom(adapter->devices, key, (GCompareFunc) device_address_cmp)) return; device = device_create(connection, adapter, key, BDADDR_BREDR); if (device) { device_set_temporary(device, FALSE); adapter->devices = g_slist_append(adapter->devices, device); } } static GSList *string_to_primary_list(char *str) { GSList *l = NULL; char **services; int i; if (str == NULL) return NULL; services = g_strsplit(str, " ", 0); if (services == NULL) return NULL; for (i = 0; services[i]; i++) { struct gatt_primary *prim; int ret; prim = g_new0(struct gatt_primary, 1); ret = sscanf(services[i], "%04hX#%04hX#%s", &prim->range.start, &prim->range.end, prim->uuid); if (ret < 3) { g_free(prim); continue; } l = g_slist_append(l, prim); } g_strfreev(services); return l; } static void create_stored_device_from_primaries(char *key, char *value, void *user_data) { struct btd_adapter *adapter = user_data; struct btd_device *device; GSList *services, *uuids, *l; char address[18]; uint8_t bdaddr_type; if (sscanf(key, "%17s#%hhu", address, &bdaddr_type) < 2) return; if (g_slist_find_custom(adapter->devices, address, (GCompareFunc) device_address_cmp)) return; device = device_create(connection, adapter, address, bdaddr_type); if (!device) return; device_set_temporary(device, FALSE); adapter->devices = g_slist_append(adapter->devices, device); services = string_to_primary_list(value); if (services == NULL) return; for (l = services, uuids = NULL; l; l = l->next) { struct gatt_primary *prim = l->data; uuids = g_slist_append(uuids, prim->uuid); } device_register_services(connection, device, services, -1); device_probe_drivers(device, uuids); g_slist_free(uuids); } static void smp_key_free(void *data) { struct smp_ltk_info *info = data; g_free(info); } static void load_devices(struct btd_adapter *adapter) { char filename[PATH_MAX + 1]; char srcaddr[18]; struct adapter_keys keys = { adapter, NULL }; int err; ba2str(&adapter->bdaddr, srcaddr); create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "profiles"); textfile_foreach(filename, create_stored_device_from_profiles, adapter); create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primaries"); textfile_foreach(filename, create_stored_device_from_primaries, adapter); create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys"); textfile_foreach(filename, create_stored_device_from_linkkeys, &keys); err = adapter_ops->load_keys(adapter->dev_id, keys.keys, main_opts.debug_keys); if (err < 0) error("Unable to load keys to adapter_ops: %s (%d)", strerror(-err), -err); g_slist_free_full(keys.keys, g_free); keys.keys = NULL; create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "longtermkeys"); textfile_foreach(filename, create_stored_device_from_ltks, &keys); err = adapter_ops->load_ltks(adapter->dev_id, keys.keys); if (err < 0) error("Unable to load keys to adapter_ops: %s (%d)", strerror(-err), -err); g_slist_free_full(keys.keys, smp_key_free); keys.keys = NULL; create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked"); textfile_foreach(filename, create_stored_device_from_blocked, adapter); } int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type) { return adapter_ops->block_device(adapter->dev_id, bdaddr, bdaddr_type); } int btd_adapter_unblock_address(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type) { return adapter_ops->unblock_device(adapter->dev_id, bdaddr, bdaddr_type); } static void clear_blocked(struct btd_adapter *adapter) { int err; err = adapter_ops->unblock_device(adapter->dev_id, BDADDR_ANY, 0); if (err < 0) error("Clearing blocked list failed: %s (%d)", strerror(-err), -err); } static void probe_driver(struct btd_adapter *adapter, gpointer user_data) { struct btd_adapter_driver *driver = user_data; int err; if (driver->probe == NULL) return; err = driver->probe(adapter); if (err < 0) { error("%s: %s (%d)", driver->name, strerror(-err), -err); return; } adapter->loaded_drivers = g_slist_prepend(adapter->loaded_drivers, driver); } static void load_drivers(struct btd_adapter *adapter) { GSList *l; for (l = adapter_drivers; l; l = l->next) probe_driver(adapter, l->data); } static void load_connections(struct btd_adapter *adapter) { GSList *l, *conns; int err; err = adapter_ops->get_conn_list(adapter->dev_id, &conns); if (err < 0) { error("Unable to fetch existing connections: %s (%d)", strerror(-err), -err); return; } for (l = conns; l != NULL; l = g_slist_next(l)) { bdaddr_t *bdaddr = l->data; struct btd_device *device; char address[18]; ba2str(bdaddr, address); DBG("Adding existing connection to %s", address); device = adapter_get_device(connection, adapter, address); if (device) adapter_add_connection(adapter, device); } g_slist_free_full(conns, g_free); } static int get_discoverable_timeout(const char *src) { int timeout; if (read_discoverable_timeout(src, &timeout) == 0) return timeout; return main_opts.discovto; } static int get_pairable_timeout(const char *src) { int timeout; if (read_pairable_timeout(src, &timeout) == 0) return timeout; return main_opts.pairto; } static void call_adapter_powered_callbacks(struct btd_adapter *adapter, gboolean powered) { GSList *l; for (l = adapter->powered_callbacks; l; l = l->next) { btd_adapter_powered_cb cb = l->data; cb(adapter, powered); } } static void emit_device_disappeared(gpointer data, gpointer user_data) { struct remote_dev_info *dev = data; struct btd_adapter *adapter = user_data; char address[18]; const char *paddr = address; ba2str(&dev->bdaddr, address); g_dbus_emit_signal(connection, adapter->path, ADAPTER_INTERFACE, "DeviceDisappeared", DBUS_TYPE_STRING, &paddr, DBUS_TYPE_INVALID); adapter->found_devices = g_slist_remove(adapter->found_devices, dev); } void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode, uint8_t *on_mode, uint16_t *discoverable_timeout, gboolean *pairable) { char str[14], address[18]; ba2str(&adapter->bdaddr, address); if (mode) { if (main_opts.remember_powered == FALSE) *mode = main_opts.mode; else if (read_device_mode(address, str, sizeof(str)) == 0) *mode = get_mode(&adapter->bdaddr, str); else *mode = main_opts.mode; } if (on_mode) *on_mode = get_mode(&adapter->bdaddr, "on"); if (discoverable_timeout) *discoverable_timeout = get_discoverable_timeout(address); if (pairable) *pairable = adapter->pairable; } void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major, uint8_t *minor) { uint8_t cls[3]; if (read_local_class(&adapter->bdaddr, cls) < 0) { uint32_t class = htobl(main_opts.class); memcpy(cls, &class, 3); } *major = cls[1]; *minor = cls[0]; } const char *btd_adapter_get_name(struct btd_adapter *adapter) { return adapter->name; } void btd_adapter_start(struct btd_adapter *adapter) { char address[18]; gboolean powered; ba2str(&adapter->bdaddr, address); adapter->dev_class = 0; adapter->off_requested = FALSE; adapter->up = TRUE; adapter->discov_timeout = get_discoverable_timeout(address); adapter->pairable_timeout = get_pairable_timeout(address); adapter->off_timer = 0; if (adapter->scan_mode & SCAN_INQUIRY) adapter->mode = MODE_DISCOVERABLE; else adapter->mode = MODE_CONNECTABLE; powered = TRUE; emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &powered); call_adapter_powered_callbacks(adapter, TRUE); adapter_ops->disable_cod_cache(adapter->dev_id); info("Adapter %s has been enabled", adapter->path); } static void reply_pending_requests(struct btd_adapter *adapter) { GSList *l; if (!adapter) return; /* pending bonding */ for (l = adapter->devices; l; l = l->next) { struct btd_device *device = l->data; if (device_is_bonding(device, NULL)) device_cancel_bonding(device, HCI_OE_USER_ENDED_CONNECTION); } } static void remove_driver(gpointer data, gpointer user_data) { struct btd_adapter_driver *driver = data; struct btd_adapter *adapter = user_data; if (driver->remove) driver->remove(adapter); } static void unload_drivers(struct btd_adapter *adapter) { g_slist_foreach(adapter->loaded_drivers, remove_driver, adapter); g_slist_free(adapter->loaded_drivers); adapter->loaded_drivers = NULL; } static void set_mode_complete(struct btd_adapter *adapter) { struct session_req *pending; const char *modestr; int err; DBG(""); if (adapter->mode == MODE_OFF) { g_slist_free_full(adapter->mode_sessions, session_free); adapter->mode_sessions = NULL; } if (adapter->pending_mode == NULL) return; pending = adapter->pending_mode; adapter->pending_mode = NULL; err = (pending->mode != adapter->mode) ? -EINVAL : 0; if (pending->msg != NULL) { DBusMessage *msg = pending->msg; DBusMessage *reply; if (err < 0) reply = btd_error_failed(msg, strerror(-err)); else { if (strcmp(dbus_message_get_member(msg), "SetProperty") == 0) adapter->global_mode = adapter->mode; reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } g_dbus_send_message(connection, reply); } modestr = mode2str(adapter->mode); DBG("%s", modestr); /* restore if the mode doesn't matches the pending */ if (err != 0) { write_device_mode(&adapter->bdaddr, modestr); error("unable to set mode: %s", mode2str(pending->mode)); } session_unref(pending); } int btd_adapter_stop(struct btd_adapter *adapter) { gboolean prop_false = FALSE; /* check pending requests */ reply_pending_requests(adapter); adapter->up = FALSE; stop_discovery(adapter); if (adapter->disc_sessions) { g_slist_free_full(adapter->disc_sessions, session_free); adapter->disc_sessions = NULL; } while (adapter->connections) { struct btd_device *device = adapter->connections->data; adapter_remove_connection(adapter, device); } if (adapter->scan_mode == (SCAN_PAGE | SCAN_INQUIRY)) emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Discoverable", DBUS_TYPE_BOOLEAN, &prop_false); if ((adapter->scan_mode & SCAN_PAGE) && adapter->pairable == TRUE) emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Pairable", DBUS_TYPE_BOOLEAN, &prop_false); if (adapter->discovering) emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Discovering", DBUS_TYPE_BOOLEAN, &prop_false); emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Powered", DBUS_TYPE_BOOLEAN, &prop_false); adapter->discovering = FALSE; adapter->scan_mode = SCAN_DISABLED; adapter->mode = MODE_OFF; adapter->off_requested = FALSE; call_adapter_powered_callbacks(adapter, FALSE); info("Adapter %s has been disabled", adapter->path); set_mode_complete(adapter); return 0; } static void off_timer_remove(struct btd_adapter *adapter) { g_source_remove(adapter->off_timer); adapter->off_timer = 0; } static void adapter_free(gpointer user_data) { struct btd_adapter *adapter = user_data; agent_free(adapter->agent); adapter->agent = NULL; DBG("%p", adapter); if (adapter->auth_idle_id) g_source_remove(adapter->auth_idle_id); if (adapter->off_timer) off_timer_remove(adapter); sdp_list_free(adapter->services, NULL); g_slist_free_full(adapter->found_devices, dev_info_free); g_slist_free(adapter->oor_devices); g_free(adapter->path); g_free(adapter->name); g_free(adapter); } struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter) { adapter->ref++; DBG("%p: ref=%d", adapter, adapter->ref); return adapter; } void btd_adapter_unref(struct btd_adapter *adapter) { gchar *path; adapter->ref--; DBG("%p: ref=%d", adapter, adapter->ref); if (adapter->ref > 0) return; path = g_strdup(adapter->path); g_dbus_unregister_interface(connection, path, ADAPTER_INTERFACE); g_free(path); } gboolean adapter_init(struct btd_adapter *adapter, gboolean up) { adapter->up = up; adapter->allow_name_changes = TRUE; adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr); if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) { error("No address available for hci%d", adapter->dev_id); return FALSE; } sdp_init_services_list(&adapter->bdaddr); if (main_opts.gatt_enabled) btd_adapter_gatt_server_start(adapter); load_drivers(adapter); clear_blocked(adapter); load_devices(adapter); /* Set pairable mode */ if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0) adapter->pairable = TRUE; /* retrieve the active connections: address the scenario where * the are active connections before the daemon've started */ load_connections(adapter); adapter->initialized = TRUE; return TRUE; } struct btd_adapter *adapter_create(DBusConnection *conn, int id) { char path[MAX_PATH_LENGTH]; struct btd_adapter *adapter; const char *base_path = manager_get_base_path(); if (!connection) connection = conn; adapter = g_try_new0(struct btd_adapter, 1); if (!adapter) { error("adapter_create: failed to alloc memory for hci%d", id); return NULL; } adapter->dev_id = id; snprintf(path, sizeof(path), "%s/hci%d", base_path, id); adapter->path = g_strdup(path); if (!g_dbus_register_interface(conn, path, ADAPTER_INTERFACE, adapter_methods, adapter_signals, NULL, adapter, adapter_free)) { error("Adapter interface init failed on path %s", path); adapter_free(adapter); return NULL; } return btd_adapter_ref(adapter); } void adapter_remove(struct btd_adapter *adapter) { GSList *l; DBG("Removing adapter %s", adapter->path); for (l = adapter->devices; l; l = l->next) device_remove(l->data, FALSE); g_slist_free(adapter->devices); unload_drivers(adapter); if (main_opts.gatt_enabled) btd_adapter_gatt_server_stop(adapter); g_slist_free(adapter->pin_callbacks); /* Return adapter to down state if it was not up on init */ adapter_ops->restore_powered(adapter->dev_id); } uint16_t adapter_get_dev_id(struct btd_adapter *adapter) { return adapter->dev_id; } const gchar *adapter_get_path(struct btd_adapter *adapter) { if (!adapter) return NULL; return adapter->path; } void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr) { bacpy(bdaddr, &adapter->bdaddr); } void adapter_set_allow_name_changes(struct btd_adapter *adapter, gboolean allow_name_changes) { adapter->allow_name_changes = allow_name_changes; } void adapter_set_discovering(struct btd_adapter *adapter, gboolean discovering) { const char *path = adapter->path; adapter->discovering = discovering; emit_property_changed(connection, path, ADAPTER_INTERFACE, "Discovering", DBUS_TYPE_BOOLEAN, &discovering); if (discovering) return; g_slist_foreach(adapter->oor_devices, emit_device_disappeared, adapter); g_slist_free_full(adapter->oor_devices, dev_info_free); adapter->oor_devices = g_slist_copy(adapter->found_devices); if (!adapter_has_discov_sessions(adapter) || adapter->discov_suspended) return; DBG("hci%u restarting discovery, disc_sessions %u", adapter->dev_id, g_slist_length(adapter->disc_sessions)); adapter->discov_id = g_idle_add(discovery_cb, adapter); } static void suspend_discovery(struct btd_adapter *adapter) { if (adapter->disc_sessions == NULL || adapter->discov_suspended) return; DBG("Suspending discovery"); if (adapter->oor_devices) { g_slist_free(adapter->oor_devices); adapter->oor_devices = NULL; } adapter->discov_suspended = TRUE; if (adapter->discov_id > 0) { g_source_remove(adapter->discov_id); adapter->discov_id = 0; } else adapter_ops->stop_discovery(adapter->dev_id); } static int found_device_cmp(gconstpointer a, gconstpointer b) { const struct remote_dev_info *d = a; const bdaddr_t *bdaddr = b; if (bacmp(bdaddr, BDADDR_ANY) == 0) return 0; return bacmp(&d->bdaddr, bdaddr); } struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr) { GSList *l; l = g_slist_find_custom(adapter->found_devices, bdaddr, found_device_cmp); if (l) return l->data; return NULL; } static int dev_rssi_cmp(struct remote_dev_info *d1, struct remote_dev_info *d2) { int rssi1, rssi2; rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi; rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi; return rssi1 - rssi2; } static void append_dict_valist(DBusMessageIter *iter, const char *first_key, va_list var_args) { DBusMessageIter dict; const char *key; int type; int n_elements; void *val; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); key = first_key; while (key) { type = va_arg(var_args, int); val = va_arg(var_args, void *); if (type == DBUS_TYPE_ARRAY) { n_elements = va_arg(var_args, int); if (n_elements > 0) dict_append_array(&dict, key, DBUS_TYPE_STRING, val, n_elements); } else dict_append_entry(&dict, key, type, val); key = va_arg(var_args, char *); } dbus_message_iter_close_container(iter, &dict); } static void emit_device_found(const char *path, const char *address, const char *first_key, ...) { DBusMessage *signal; DBusMessageIter iter; va_list var_args; signal = dbus_message_new_signal(path, ADAPTER_INTERFACE, "DeviceFound"); if (!signal) { error("Unable to allocate new %s.DeviceFound signal", ADAPTER_INTERFACE); return; } dbus_message_iter_init_append(signal, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &address); va_start(var_args, first_key); append_dict_valist(&iter, first_key, var_args); va_end(var_args); g_dbus_send_message(connection, signal); } static char **strlist2array(GSList *list) { unsigned int i, n; char **array; if (list == NULL) return NULL; n = g_slist_length(list); array = g_new0(char *, n + 1); for (i = 0; list; list = list->next, i++) array[i] = g_strdup((const gchar *) list->data); return array; } void adapter_emit_device_found(struct btd_adapter *adapter, struct remote_dev_info *dev) { struct btd_device *device; char peer_addr[18], local_addr[18]; const char *icon, *paddr = peer_addr; dbus_bool_t paired = FALSE, trusted = FALSE; dbus_int16_t rssi = dev->rssi; char *alias; size_t uuid_count; ba2str(&dev->bdaddr, peer_addr); ba2str(&adapter->bdaddr, local_addr); device = adapter_find_device(adapter, paddr); if (device) { paired = device_is_paired(device); trusted = device_is_trusted(device); } /* The uuids string array is updated only if necessary */ uuid_count = g_slist_length(dev->services); if (dev->services && dev->uuid_count != uuid_count) { g_strfreev(dev->uuids); dev->uuids = strlist2array(dev->services); dev->uuid_count = uuid_count; } if (!dev->alias) { if (!dev->name) { alias = g_strdup(peer_addr); g_strdelimit(alias, ":", '-'); } else alias = g_strdup(dev->name); } else alias = g_strdup(dev->alias); if (dev->bdaddr_type != BDADDR_BREDR) { gboolean broadcaster; uint16_t app; if (dev->flags & (EIR_LIM_DISC | EIR_GEN_DISC)) broadcaster = FALSE; else broadcaster = TRUE; dev->legacy = FALSE; if (read_remote_appearance(&adapter->bdaddr, &dev->bdaddr, dev->bdaddr_type, &app) == 0) icon = gap_appearance_to_icon(app); else icon = NULL; emit_device_found(adapter->path, paddr, "Address", DBUS_TYPE_STRING, &paddr, "Class", DBUS_TYPE_UINT32, &dev->class, "Icon", DBUS_TYPE_STRING, &icon, "RSSI", DBUS_TYPE_INT16, &rssi, "Name", DBUS_TYPE_STRING, &dev->name, "Alias", DBUS_TYPE_STRING, &alias, "LegacyPairing", DBUS_TYPE_BOOLEAN, &dev->legacy, "Paired", DBUS_TYPE_BOOLEAN, &paired, "Broadcaster", DBUS_TYPE_BOOLEAN, &broadcaster, "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count, NULL); } else { icon = class_to_icon(dev->class); emit_device_found(adapter->path, paddr, "Address", DBUS_TYPE_STRING, &paddr, "Class", DBUS_TYPE_UINT32, &dev->class, "Icon", DBUS_TYPE_STRING, &icon, "RSSI", DBUS_TYPE_INT16, &rssi, "Name", DBUS_TYPE_STRING, &dev->name, "Alias", DBUS_TYPE_STRING, &alias, "LegacyPairing", DBUS_TYPE_BOOLEAN, &dev->legacy, "Paired", DBUS_TYPE_BOOLEAN, &paired, "Trusted", DBUS_TYPE_BOOLEAN, &trusted, "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count, NULL); } g_free(alias); } static struct remote_dev_info *found_device_new(const bdaddr_t *bdaddr, uint8_t bdaddr_type, const char *name, const char *alias, uint32_t class, gboolean legacy, int flags) { struct remote_dev_info *dev; dev = g_new0(struct remote_dev_info, 1); bacpy(&dev->bdaddr, bdaddr); dev->bdaddr_type = bdaddr_type; dev->name = g_strdup(name); dev->alias = g_strdup(alias); dev->class = class; dev->legacy = legacy; if (flags >= 0) dev->flags = flags; return dev; } static void remove_same_uuid(gpointer data, gpointer user_data) { struct remote_dev_info *dev = user_data; GSList *l; for (l = dev->services; l; l = l->next) { char *current_uuid = l->data; char *new_uuid = data; if (strcmp(current_uuid, new_uuid) == 0) { g_free(current_uuid); dev->services = g_slist_delete_link(dev->services, l); break; } } } static void dev_prepend_uuid(gpointer data, gpointer user_data) { struct remote_dev_info *dev = user_data; char *new_uuid = data; dev->services = g_slist_prepend(dev->services, g_strdup(new_uuid)); } static gboolean pairing_is_legacy(bdaddr_t *local, bdaddr_t *peer, const uint8_t *eir, const char *name) { unsigned char features[8]; if (eir) return FALSE; if (name == NULL) return TRUE; if (read_remote_features(local, peer, NULL, features) < 0) return TRUE; if (features[0] & 0x01) return FALSE; else return TRUE; } static char *read_stored_data(bdaddr_t *local, bdaddr_t *peer, const char *file) { char local_addr[18], peer_addr[18], filename[PATH_MAX + 1]; ba2str(local, local_addr); ba2str(peer, peer_addr); create_name(filename, PATH_MAX, STORAGEDIR, local_addr, file); return textfile_get(filename, peer_addr); } void adapter_update_found_devices(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type, int8_t rssi, uint8_t confirm_name, uint8_t *data, uint8_t data_len) { struct remote_dev_info *dev; struct eir_data eir_data; char *alias, *name; gboolean legacy, name_known; uint32_t dev_class; int err; memset(&eir_data, 0, sizeof(eir_data)); err = eir_parse(&eir_data, data, data_len); if (err < 0) { error("Error parsing EIR data: %s (%d)", strerror(-err), -err); return; } dev_class = eir_data.dev_class[0] | (eir_data.dev_class[1] << 8) | (eir_data.dev_class[2] << 16); if (dev_class != 0) write_remote_class(&adapter->bdaddr, bdaddr, dev_class); if (eir_data.appearance != 0) write_remote_appearance(&adapter->bdaddr, bdaddr, bdaddr_type, eir_data.appearance); if (eir_data.name != NULL && eir_data.name_complete) write_device_name(&adapter->bdaddr, bdaddr, eir_data.name); dev = adapter_search_found_devices(adapter, bdaddr); if (dev) { adapter->oor_devices = g_slist_remove(adapter->oor_devices, dev); /* If an existing device had no name but the newly received EIR * data has (complete or not), we want to present it to the * user. */ if (dev->name == NULL && eir_data.name != NULL) { dev->name = g_strdup(eir_data.name); goto done; } if (dev->rssi != rssi) goto done; eir_data_free(&eir_data); return; } /* New device in the discovery session */ name = read_stored_data(&adapter->bdaddr, bdaddr, "names"); if (bdaddr_type == BDADDR_BREDR) { legacy = pairing_is_legacy(&adapter->bdaddr, bdaddr, data, name); if (!name && main_opts.name_resolv && adapter_has_discov_sessions(adapter)) name_known = FALSE; else name_known = TRUE; } else { legacy = FALSE; name_known = TRUE; } if (confirm_name) adapter_ops->confirm_name(adapter->dev_id, bdaddr, bdaddr_type, name_known); alias = read_stored_data(&adapter->bdaddr, bdaddr, "aliases"); dev = found_device_new(bdaddr, bdaddr_type, name, alias, dev_class, legacy, eir_data.flags); free(name); free(alias); adapter->found_devices = g_slist_prepend(adapter->found_devices, dev); done: dev->rssi = rssi; adapter->found_devices = g_slist_sort(adapter->found_devices, (GCompareFunc) dev_rssi_cmp); g_slist_foreach(eir_data.services, remove_same_uuid, dev); g_slist_foreach(eir_data.services, dev_prepend_uuid, dev); adapter_emit_device_found(adapter, dev); eir_data_free(&eir_data); } void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode) { const gchar *path = adapter_get_path(adapter); gboolean discoverable, pairable; DBG("old 0x%02x new 0x%02x", adapter->scan_mode, scan_mode); if (adapter->scan_mode == scan_mode) return; switch (scan_mode) { case SCAN_DISABLED: adapter->mode = MODE_OFF; discoverable = FALSE; pairable = FALSE; break; case SCAN_PAGE: adapter->mode = MODE_CONNECTABLE; discoverable = FALSE; pairable = adapter->pairable; break; case (SCAN_PAGE | SCAN_INQUIRY): adapter->mode = MODE_DISCOVERABLE; discoverable = TRUE; pairable = adapter->pairable; break; default: /* ignore, reserved */ return; } /* If page scanning gets toggled emit the Pairable property */ if ((adapter->scan_mode & SCAN_PAGE) != (scan_mode & SCAN_PAGE)) emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE, "Pairable", DBUS_TYPE_BOOLEAN, &pairable); emit_property_changed(connection, path, ADAPTER_INTERFACE, "Discoverable", DBUS_TYPE_BOOLEAN, &discoverable); adapter->scan_mode = scan_mode; set_mode_complete(adapter); } struct agent *adapter_get_agent(struct btd_adapter *adapter) { if (!adapter) return NULL; return adapter->agent; } void adapter_add_connection(struct btd_adapter *adapter, struct btd_device *device) { if (g_slist_find(adapter->connections, device)) { error("Device is already marked as connected"); return; } device_add_connection(device, connection); adapter->connections = g_slist_append(adapter->connections, device); } void adapter_remove_connection(struct btd_adapter *adapter, struct btd_device *device) { DBG(""); if (!g_slist_find(adapter->connections, device)) { error("No matching connection for device"); return; } device_remove_connection(device, connection); adapter->connections = g_slist_remove(adapter->connections, device); if (device_is_authenticating(device)) device_cancel_authentication(device, TRUE); if (device_is_temporary(device)) { const char *path = device_get_path(device); DBG("Removing temporary device %s", path); adapter_remove_device(connection, adapter, device, TRUE); } } gboolean adapter_has_discov_sessions(struct btd_adapter *adapter) { if (!adapter || !adapter->disc_sessions) return FALSE; return TRUE; } int btd_register_adapter_driver(struct btd_adapter_driver *driver) { adapter_drivers = g_slist_append(adapter_drivers, driver); if (driver->probe == NULL) return 0; manager_foreach_adapter(probe_driver, driver); return 0; } static void unload_driver(struct btd_adapter *adapter, gpointer data) { adapter->loaded_drivers = g_slist_remove(adapter->loaded_drivers, data); } void btd_unregister_adapter_driver(struct btd_adapter_driver *driver) { adapter_drivers = g_slist_remove(adapter_drivers, driver); manager_foreach_adapter(unload_driver, driver); } static void agent_auth_cb(struct agent *agent, DBusError *derr, void *user_data) { struct service_auth *auth = user_data; device_set_authorizing(auth->device, FALSE); auth->cb(derr, auth->user_data); } static gboolean auth_idle_cb(gpointer user_data) { struct service_auth *auth = user_data; struct btd_adapter *adapter = auth->adapter; adapter->auth_idle_id = 0; auth->cb(NULL, auth->user_data); return FALSE; } static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst, const char *uuid, service_auth_cb cb, void *user_data) { struct service_auth *auth; struct btd_device *device; struct agent *agent; char address[18]; const gchar *dev_path; int err; ba2str(dst, address); device = adapter_find_device(adapter, address); if (!device) return -EPERM; /* Device connected? */ if (!g_slist_find(adapter->connections, device)) error("Authorization request for non-connected device!?"); if (adapter->auth_idle_id) return -EBUSY; auth = g_try_new0(struct service_auth, 1); if (!auth) return -ENOMEM; auth->cb = cb; auth->user_data = user_data; auth->device = device; auth->adapter = adapter; if (device_is_trusted(device) == TRUE) { adapter->auth_idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, auth_idle_cb, auth, g_free); return 0; } agent = device_get_agent(device); if (!agent) { warn("Can't find device agent"); g_free(auth); return -EPERM; } dev_path = device_get_path(device); err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, auth, g_free); if (err < 0) g_free(auth); else device_set_authorizing(device, TRUE); return err; } int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst, const char *uuid, service_auth_cb cb, void *user_data) { struct btd_adapter *adapter; GSList *l; if (bacmp(src, BDADDR_ANY) != 0) { adapter = manager_find_adapter(src); if (!adapter) return -EPERM; return adapter_authorize(adapter, dst, uuid, cb, user_data); } for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) { int err; adapter = l->data; err = adapter_authorize(adapter, dst, uuid, cb, user_data); if (err == 0) return 0; } return -EPERM; } int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst) { struct btd_adapter *adapter = manager_find_adapter(src); struct btd_device *device; struct agent *agent; char address[18]; int err; if (!adapter) return -EPERM; ba2str(dst, address); device = adapter_find_device(adapter, address); if (!device) return -EPERM; if (adapter->auth_idle_id) { g_source_remove(adapter->auth_idle_id); adapter->auth_idle_id = 0; return 0; } /* * FIXME: Cancel fails if authorization is requested to adapter's * agent and in the meanwhile CreatePairedDevice is called. */ agent = device_get_agent(device); if (!agent) return -EPERM; err = agent_cancel(agent); if (err == 0) device_set_authorizing(device, FALSE); return err; } static gchar *adapter_any_path = NULL; static int adapter_any_refcount = 0; const char *adapter_any_get_path(void) { return adapter_any_path; } const char *btd_adapter_any_request_path(void) { if (adapter_any_refcount++ > 0) return adapter_any_path; adapter_any_path = g_strdup_printf("%s/any", manager_get_base_path()); return adapter_any_path; } void btd_adapter_any_release_path(void) { adapter_any_refcount--; if (adapter_any_refcount > 0) return; g_free(adapter_any_path); adapter_any_path = NULL; } gboolean adapter_powering_down(struct btd_adapter *adapter) { return adapter->off_requested; } int btd_adapter_restore_powered(struct btd_adapter *adapter) { char mode[14], address[18]; if (!adapter_ops) return -EINVAL; if (!main_opts.remember_powered) return -EINVAL; if (adapter->up) return 0; ba2str(&adapter->bdaddr, address); if (read_device_mode(address, mode, sizeof(mode)) == 0 && g_str_equal(mode, "off")) return 0; return adapter_ops->set_powered(adapter->dev_id, TRUE); } static gboolean switch_off_timeout(gpointer user_data) { struct btd_adapter *adapter = user_data; adapter_ops->set_powered(adapter->dev_id, FALSE); adapter->off_timer = 0; return FALSE; } int btd_adapter_switch_online(struct btd_adapter *adapter) { if (!adapter_ops) return -EINVAL; if (adapter->up) return -EALREADY; if (adapter->off_timer) off_timer_remove(adapter); return adapter_ops->set_powered(adapter->dev_id, TRUE); } int btd_adapter_switch_offline(struct btd_adapter *adapter) { if (!adapter_ops) return -EINVAL; if (!adapter->up) return -EALREADY; if (adapter->off_timer) return 0; adapter->global_mode = MODE_OFF; if (adapter->connections == NULL) return adapter_ops->set_powered(adapter->dev_id, FALSE); g_slist_foreach(adapter->connections, (GFunc) device_request_disconnect, NULL); adapter->off_timer = g_timeout_add_seconds(OFF_TIMER, switch_off_timeout, adapter); return 0; } static gboolean disable_auto(gpointer user_data) { struct btd_adapter *adapter = user_data; GSList *l; for (l = adapter->devices; l; l = l->next) { struct btd_device *device = l->data; device_set_auto_connect(device, FALSE); } adapter->auto_timeout_id = 0; return FALSE; } static void set_auto_connect(gpointer data, gpointer user_data) { struct btd_device *device = data; device_set_auto_connect(device, TRUE); } void btd_adapter_enable_auto_connect(struct btd_adapter *adapter) { if (!adapter->up) return; DBG("Enabling automatic connections"); if (adapter->auto_timeout_id) return; g_slist_foreach(adapter->devices, set_auto_connect, NULL); adapter->auto_timeout_id = g_timeout_add_seconds(main_opts.autoto, disable_auto, adapter); } void btd_adapter_register_pin_cb(struct btd_adapter *adapter, btd_adapter_pin_cb_t cb) { adapter->pin_callbacks = g_slist_prepend(adapter->pin_callbacks, cb); } void btd_adapter_unregister_pin_cb(struct btd_adapter *adapter, btd_adapter_pin_cb_t cb) { adapter->pin_callbacks = g_slist_remove(adapter->pin_callbacks, cb); } ssize_t btd_adapter_get_pin(struct btd_adapter *adapter, struct btd_device *dev, char *pin_buf, gboolean *display) { GSList *l; btd_adapter_pin_cb_t cb; bdaddr_t sba, dba; ssize_t ret; for (l = adapter->pin_callbacks; l != NULL; l = g_slist_next(l)) { cb = l->data; ret = cb(adapter, dev, pin_buf, display); if (ret > 0) return ret; } adapter_get_address(adapter, &sba); device_get_address(dev, &dba, NULL); return read_pin_code(&sba, &dba, pin_buf); } int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority) { if (ops->setup == NULL) return -EINVAL; if (priority) ops_candidates = g_slist_prepend(ops_candidates, ops); else ops_candidates = g_slist_append(ops_candidates, ops); return 0; } void btd_adapter_cleanup_ops(struct btd_adapter_ops *ops) { ops_candidates = g_slist_remove(ops_candidates, ops); ops->cleanup(); if (adapter_ops == ops) adapter_ops = NULL; } int adapter_ops_setup(void) { GSList *l; int ret; if (!ops_candidates) return -EINVAL; for (l = ops_candidates; l != NULL; l = g_slist_next(l)) { struct btd_adapter_ops *ops = l->data; ret = ops->setup(); if (ret < 0) continue; adapter_ops = ops; break; } return ret; } void btd_adapter_register_powered_callback(struct btd_adapter *adapter, btd_adapter_powered_cb cb) { adapter->powered_callbacks = g_slist_append(adapter->powered_callbacks, cb); } void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter, btd_adapter_powered_cb cb) { adapter->powered_callbacks = g_slist_remove(adapter->powered_callbacks, cb); } int btd_adapter_set_fast_connectable(struct btd_adapter *adapter, gboolean enable) { if (!adapter_ops) return -EINVAL; if (!adapter->up) return -EINVAL; return adapter_ops->set_fast_connectable(adapter->dev_id, enable); } int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr, int which, int timeout, uint32_t *clock, uint16_t *accuracy) { if (!adapter_ops) return -EINVAL; if (!adapter->up) return -EINVAL; return adapter_ops->read_clock(adapter->dev_id, bdaddr, which, timeout, clock, accuracy); } int btd_adapter_disconnect_device(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type) { return adapter_ops->disconnect(adapter->dev_id, bdaddr, bdaddr_type); } int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type) { return adapter_ops->remove_bonding(adapter->dev_id, bdaddr, bdaddr_type); } int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr, const char *pin, size_t pin_len) { return adapter_ops->pincode_reply(adapter->dev_id, bdaddr, pin, pin_len); } int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type, gboolean success) { return adapter_ops->confirm_reply(adapter->dev_id, bdaddr, bdaddr_type, success); } int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t bdaddr_type, uint32_t passkey) { return adapter_ops->passkey_reply(adapter->dev_id, bdaddr, bdaddr_type, passkey); } int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr, bt_hci_result_t cb, gpointer user_data) { return adapter_ops->encrypt_link(adapter->dev_id, bdaddr, cb, user_data); } int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor, uint16_t product, uint16_t version, uint16_t source) { return adapter_ops->set_did(adapter->dev_id, vendor, product, version, source); } int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t addr_type, uint8_t io_cap) { suspend_discovery(adapter); return adapter_ops->create_bonding(adapter->dev_id, bdaddr, addr_type, io_cap); } int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr) { return adapter_ops->cancel_bonding(adapter->dev_id, bdaddr); } void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t status) { struct btd_device *device; char addr[18]; ba2str(bdaddr, addr); if (status == 0) device = adapter_get_device(connection, adapter, addr); else device = adapter_find_device(adapter, addr); if (device != NULL) device_bonding_complete(device, status); if (adapter->discov_suspended) { adapter->discov_suspended = FALSE; adapter_ops->start_discovery(adapter->dev_id); } } int btd_adapter_read_local_oob_data(struct btd_adapter *adapter) { return adapter_ops->read_local_oob_data(adapter->dev_id); } int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter, bdaddr_t *bdaddr, uint8_t *hash, uint8_t *randomizer) { return adapter_ops->add_remote_oob_data(adapter->dev_id, bdaddr, hash, randomizer); } int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter, bdaddr_t *bdaddr) { return adapter_ops->remove_remote_oob_data(adapter->dev_id, bdaddr); } bluez-4.101/src/sdpd-request.c0000644000000000000000000007000511766125764013123 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2001-2002 Nokia Corporation * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * Copyright (C) 2002-2003 Stephen Crane * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include "sdpd.h" #include "log.h" typedef struct { uint32_t timestamp; union { uint16_t maxBytesSent; uint16_t lastIndexSent; } cStateValue; } sdp_cont_state_t; #define SDP_CONT_STATE_SIZE (sizeof(uint8_t) + sizeof(sdp_cont_state_t)) #define MIN(x, y) ((x) < (y)) ? (x): (y) typedef struct _sdp_cstate_list sdp_cstate_list_t; struct _sdp_cstate_list { sdp_cstate_list_t *next; uint32_t timestamp; sdp_buf_t buf; }; static sdp_cstate_list_t *cstates; /* FIXME: should probably remove it when it's found */ static sdp_buf_t *sdp_get_cached_rsp(sdp_cont_state_t *cstate) { sdp_cstate_list_t *p; for (p = cstates; p; p = p->next) if (p->timestamp == cstate->timestamp) return &p->buf; return 0; } static uint32_t sdp_cstate_alloc_buf(sdp_buf_t *buf) { sdp_cstate_list_t *cstate = malloc(sizeof(sdp_cstate_list_t)); uint8_t *data = malloc(buf->data_size); memcpy(data, buf->data, buf->data_size); memset((char *)cstate, 0, sizeof(sdp_cstate_list_t)); cstate->buf.data = data; cstate->buf.data_size = buf->data_size; cstate->buf.buf_size = buf->data_size; cstate->timestamp = sdp_get_time(); cstate->next = cstates; cstates = cstate; return cstate->timestamp; } /* Additional values for checking datatype (not in spec) */ #define SDP_TYPE_UUID 0xfe #define SDP_TYPE_ATTRID 0xff struct attrid { uint8_t dtd; union { uint16_t uint16; uint32_t uint32; }; }; /* * Generic data element sequence extractor. Builds * a list whose elements are those found in the * sequence. The data type of elements found in the * sequence is returned in the reference pDataType */ static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *pDataType, uint8_t expectedType) { uint8_t seqType; int scanned, data_size = 0; short numberOfElements = 0; int seqlen = 0; sdp_list_t *pSeq = NULL; uint8_t dataType; int status = 0; const uint8_t *p; size_t bufsize; scanned = sdp_extract_seqtype(buf, len, &seqType, &data_size); SDPDBG("Seq type : %d", seqType); if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) { error("Unknown seq type"); return -1; } p = buf + scanned; bufsize = len - scanned; SDPDBG("Data size : %d", data_size); for (;;) { char *pElem = NULL; int localSeqLength = 0; if (bufsize < sizeof(uint8_t)) { SDPDBG("->Unexpected end of buffer"); goto failed; } dataType = *p; SDPDBG("Data type: 0x%02x", dataType); if (expectedType == SDP_TYPE_UUID) { if (dataType != SDP_UUID16 && dataType != SDP_UUID32 && dataType != SDP_UUID128) { SDPDBG("->Unexpected Data type (expected UUID_ANY)"); goto failed; } } else if (expectedType == SDP_TYPE_ATTRID && (dataType != SDP_UINT16 && dataType != SDP_UINT32)) { SDPDBG("->Unexpected Data type (expected 0x%02x or 0x%02x)", SDP_UINT16, SDP_UINT32); goto failed; } else if (expectedType != SDP_TYPE_ATTRID && dataType != expectedType) { SDPDBG("->Unexpected Data type (expected 0x%02x)", expectedType); goto failed; } switch (dataType) { case SDP_UINT16: p += sizeof(uint8_t); seqlen += sizeof(uint8_t); bufsize -= sizeof(uint8_t); if (bufsize < sizeof(uint16_t)) { SDPDBG("->Unexpected end of buffer"); goto failed; } if (expectedType == SDP_TYPE_ATTRID) { struct attrid *aid; aid = malloc(sizeof(struct attrid)); aid->dtd = dataType; bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)&aid->uint16); pElem = (char *) aid; } else { pElem = malloc(sizeof(uint16_t)); bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem); } p += sizeof(uint16_t); seqlen += sizeof(uint16_t); bufsize -= sizeof(uint16_t); break; case SDP_UINT32: p += sizeof(uint8_t); seqlen += sizeof(uint8_t); bufsize -= sizeof(uint8_t); if (bufsize < (int)sizeof(uint32_t)) { SDPDBG("->Unexpected end of buffer"); goto failed; } if (expectedType == SDP_TYPE_ATTRID) { struct attrid *aid; aid = malloc(sizeof(struct attrid)); aid->dtd = dataType; bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)&aid->uint32); pElem = (char *) aid; } else { pElem = malloc(sizeof(uint32_t)); bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem); } p += sizeof(uint32_t); seqlen += sizeof(uint32_t); bufsize -= sizeof(uint32_t); break; case SDP_UUID16: case SDP_UUID32: case SDP_UUID128: pElem = malloc(sizeof(uuid_t)); status = sdp_uuid_extract(p, bufsize, (uuid_t *) pElem, &localSeqLength); if (status < 0) { free(pElem); goto failed; } seqlen += localSeqLength; p += localSeqLength; bufsize -= localSeqLength; break; default: return -1; } if (status == 0) { pSeq = sdp_list_append(pSeq, pElem); numberOfElements++; SDPDBG("No of elements : %d", numberOfElements); if (seqlen == data_size) break; else if (seqlen > data_size || seqlen > len) goto failed; } else free(pElem); } *svcReqSeq = pSeq; scanned += seqlen; *pDataType = dataType; return scanned; failed: sdp_list_free(pSeq, free); return -1; } static int sdp_set_cstate_pdu(sdp_buf_t *buf, sdp_cont_state_t *cstate) { uint8_t *pdata = buf->data + buf->data_size; int length = 0; if (cstate) { SDPDBG("Non null sdp_cstate_t id : 0x%x", cstate->timestamp); *pdata = sizeof(sdp_cont_state_t); pdata += sizeof(uint8_t); length += sizeof(uint8_t); memcpy(pdata, cstate, sizeof(sdp_cont_state_t)); length += sizeof(sdp_cont_state_t); } else { /* set "null" continuation state */ *pdata = 0; length += sizeof(uint8_t); } buf->data_size += length; return length; } static int sdp_cstate_get(uint8_t *buffer, size_t len, sdp_cont_state_t **cstate) { uint8_t cStateSize = *buffer; SDPDBG("Continuation State size : %d", cStateSize); if (cStateSize == 0) { *cstate = NULL; return 0; } buffer++; len--; if (len < sizeof(sdp_cont_state_t)) return -EINVAL; /* * Check if continuation state exists, if yes attempt * to get response remainder from cache, else send error */ *cstate = malloc(sizeof(sdp_cont_state_t)); if (!(*cstate)) return -ENOMEM; memcpy(*cstate, buffer, sizeof(sdp_cont_state_t)); SDPDBG("Cstate TS : 0x%x", (*cstate)->timestamp); SDPDBG("Bytes sent : %d", (*cstate)->cStateValue.maxBytesSent); return 0; } /* * The matching process is defined as "each and every UUID * specified in the "search pattern" must be present in the * "target pattern". Here "search pattern" is the set of UUIDs * specified by the service discovery client and "target pattern" * is the set of UUIDs present in a service record. * * Return 1 if each and every UUID in the search * pattern exists in the target pattern, 0 if the * match succeeds and -1 on error. */ static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern) { /* * The target is a sorted list, so we need not look * at all elements to confirm existence of an element * from the search pattern */ int patlen = sdp_list_len(pattern); if (patlen < sdp_list_len(search)) return -1; for (; search; search = search->next) { uuid_t *uuid128; void *data = search->data; sdp_list_t *list; if (data == NULL) return -1; /* create 128-bit form of the search UUID */ uuid128 = sdp_uuid_to_uuid128((uuid_t *)data); list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp); bt_free(uuid128); if (!list) return 0; } return 1; } /* * Service search request PDU. This method extracts the search pattern * (a sequence of UUIDs) and calls the matching function * to find matching services */ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf) { int status = 0, i, plen, mlen, mtu, scanned; sdp_list_t *pattern = NULL; uint16_t expected, actual, rsp_count = 0; uint8_t dtd; sdp_cont_state_t *cstate = NULL; uint8_t *pCacheBuffer = NULL; int handleSize = 0; uint32_t cStateId = 0; short *pTotalRecordCount, *pCurrentRecordCount; uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t); size_t data_left = req->len - sizeof(sdp_pdu_hdr_t); scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID); if (scanned == -1) { status = SDP_INVALID_SYNTAX; goto done; } pdata += scanned; data_left -= scanned; plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); mlen = scanned + sizeof(uint16_t) + 1; /* ensure we don't read past buffer */ if (plen < mlen || plen != mlen + *(uint8_t *)(pdata+sizeof(uint16_t))) { status = SDP_INVALID_SYNTAX; goto done; } if (data_left < sizeof(uint16_t)) { status = SDP_INVALID_SYNTAX; goto done; } expected = ntohs(bt_get_unaligned((uint16_t *)pdata)); SDPDBG("Expected count: %d", expected); SDPDBG("Bytes scanned : %d", scanned); pdata += sizeof(uint16_t); data_left -= sizeof(uint16_t); /* * Check if continuation state exists, if yes attempt * to get rsp remainder from cache, else send error */ if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { status = SDP_INVALID_SYNTAX; goto done; } mtu = req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint16_t) - sizeof(uint16_t) - SDP_CONT_STATE_SIZE; actual = MIN(expected, mtu >> 2); /* make space in the rsp buffer for total and current record counts */ pdata = buf->data; /* total service record count = 0 */ pTotalRecordCount = (short *)pdata; bt_put_unaligned(0, (uint16_t *)pdata); pdata += sizeof(uint16_t); buf->data_size += sizeof(uint16_t); /* current service record count = 0 */ pCurrentRecordCount = (short *)pdata; bt_put_unaligned(0, (uint16_t *)pdata); pdata += sizeof(uint16_t); buf->data_size += sizeof(uint16_t); if (cstate == NULL) { /* for every record in the DB, do a pattern search */ sdp_list_t *list = sdp_get_record_list(); handleSize = 0; for (; list && rsp_count < expected; list = list->next) { sdp_record_t *rec = list->data; SDPDBG("Checking svcRec : 0x%x", rec->handle); if (sdp_match_uuid(pattern, rec->pattern) > 0 && sdp_check_access(rec->handle, &req->device)) { rsp_count++; bt_put_unaligned(htonl(rec->handle), (uint32_t *)pdata); pdata += sizeof(uint32_t); handleSize += sizeof(uint32_t); } } SDPDBG("Match count: %d", rsp_count); buf->data_size += handleSize; bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount); bt_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount); if (rsp_count > actual) { /* cache the rsp and generate a continuation state */ cStateId = sdp_cstate_alloc_buf(buf); /* * subtract handleSize since we now send only * a subset of handles */ buf->data_size -= handleSize; } else { /* NULL continuation state */ sdp_set_cstate_pdu(buf, NULL); } } /* under both the conditions below, the rsp buffer is not built yet */ if (cstate || cStateId > 0) { short lastIndex = 0; if (cstate) { /* * Get the previous sdp_cont_state_t and obtain * the cached rsp */ sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); if (pCache) { pCacheBuffer = pCache->data; /* get the rsp_count from the cached buffer */ rsp_count = ntohs(bt_get_unaligned((uint16_t *)pCacheBuffer)); /* get index of the last sdp_record_t sent */ lastIndex = cstate->cStateValue.lastIndexSent; } else { status = SDP_INVALID_CSTATE; goto done; } } else { pCacheBuffer = buf->data; lastIndex = 0; } /* * Set the local buffer pointer to after the * current record count and increment the cached * buffer pointer to beyond the counters */ pdata = (uint8_t *) pCurrentRecordCount + sizeof(uint16_t); /* increment beyond the totalCount and the currentCount */ pCacheBuffer += 2 * sizeof(uint16_t); if (cstate) { handleSize = 0; for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) { bt_put_unaligned(bt_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata); pdata += sizeof(uint32_t); handleSize += sizeof(uint32_t); } } else { handleSize = actual << 2; i = actual; } buf->data_size += handleSize; bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount); bt_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount); if (i == rsp_count) { /* set "null" continuationState */ sdp_set_cstate_pdu(buf, NULL); } else { /* * there's more: set lastIndexSent to * the new value and move on */ sdp_cont_state_t newState; SDPDBG("Setting non-NULL sdp_cstate_t"); if (cstate) memcpy(&newState, cstate, sizeof(sdp_cont_state_t)); else { memset(&newState, 0, sizeof(sdp_cont_state_t)); newState.timestamp = cStateId; } newState.cStateValue.lastIndexSent = i; sdp_set_cstate_pdu(buf, &newState); } } done: free(cstate); if (pattern) sdp_list_free(pattern, free); return status; } /* * Extract attribute identifiers from the request PDU. * Clients could request a subset of attributes (by id) * from a service record, instead of the whole set. The * requested identifiers are present in the PDU form of * the request */ static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, sdp_buf_t *buf) { sdp_buf_t pdu; if (!rec) return SDP_INVALID_RECORD_HANDLE; if (seq == NULL) { SDPDBG("Attribute sequence is NULL"); return 0; } SDPDBG("Entries in attr seq : %d", sdp_list_len(seq)); sdp_gen_record_pdu(rec, &pdu); for (; seq; seq = seq->next) { struct attrid *aid = seq->data; SDPDBG("AttrDataType : %d", aid->dtd); if (aid->dtd == SDP_UINT16) { uint16_t attr = bt_get_unaligned((uint16_t *)&aid->uint16); sdp_data_t *a = sdp_data_get(rec, attr); if (a) sdp_append_to_pdu(buf, a); } else if (aid->dtd == SDP_UINT32) { uint32_t range = bt_get_unaligned((uint32_t *)&aid->uint32); uint16_t attr; uint16_t low = (0xffff0000 & range) >> 16; uint16_t high = 0x0000ffff & range; sdp_data_t *data; SDPDBG("attr range : 0x%x", range); SDPDBG("Low id : 0x%x", low); SDPDBG("High id : 0x%x", high); if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) { /* copy it */ memcpy(buf->data, pdu.data, pdu.data_size); buf->data_size = pdu.data_size; break; } /* (else) sub-range of attributes */ for (attr = low; attr < high; attr++) { data = sdp_data_get(rec, attr); if (data) sdp_append_to_pdu(buf, data); } data = sdp_data_get(rec, high); if (data) sdp_append_to_pdu(buf, data); } else { error("Unexpected data type : 0x%x", aid->dtd); error("Expect uint16_t or uint32_t"); free(pdu.data); return SDP_INVALID_SYNTAX; } } free(pdu.data); return 0; } /* * A request for the attributes of a service record. * First check if the service record (specified by * service record handle) exists, then call the attribute * streaming function */ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf) { sdp_cont_state_t *cstate = NULL; uint8_t *pResponse = NULL; short cstate_size = 0; sdp_list_t *seq = NULL; uint8_t dtd = 0; int scanned = 0; unsigned int max_rsp_size; int status = 0, plen, mlen; uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t); size_t data_left = req->len - sizeof(sdp_pdu_hdr_t); uint32_t handle; if (data_left < sizeof(uint32_t)) { status = SDP_INVALID_SYNTAX; goto done; } handle = ntohl(bt_get_unaligned((uint32_t *)pdata)); pdata += sizeof(uint32_t); data_left -= sizeof(uint32_t); if (data_left < sizeof(uint16_t)) { status = SDP_INVALID_SYNTAX; goto done; } max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata)); pdata += sizeof(uint16_t); data_left -= sizeof(uint16_t); if (data_left < sizeof(sdp_pdu_hdr_t)) { status = SDP_INVALID_SYNTAX; goto done; } /* extract the attribute list */ scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID); if (scanned == -1) { status = SDP_INVALID_SYNTAX; goto done; } pdata += scanned; data_left -= scanned; plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); mlen = scanned + sizeof(uint32_t) + sizeof(uint16_t) + 1; /* ensure we don't read past buffer */ if (plen < mlen || plen != mlen + *(uint8_t *)pdata) { status = SDP_INVALID_PDU_SIZE; goto done; } /* * if continuation state exists, attempt * to get rsp remainder from cache, else send error */ if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { status = SDP_INVALID_SYNTAX; goto done; } SDPDBG("SvcRecHandle : 0x%x", handle); SDPDBG("max_rsp_size : %d", max_rsp_size); /* * Check that max_rsp_size is within valid range * a minimum size of 0x0007 has to be used for data field */ if (max_rsp_size < 0x0007) { status = SDP_INVALID_SYNTAX; goto done; } /* * Calculate Attribute size according to MTU * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t)) */ max_rsp_size = MIN(max_rsp_size, req->mtu - sizeof(sdp_pdu_hdr_t) - sizeof(uint32_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t)); /* pull header for AttributeList byte count */ buf->data += sizeof(uint16_t); buf->buf_size -= sizeof(uint16_t); if (cstate) { sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); SDPDBG("Obtained cached rsp : %p", pCache); if (pCache) { short sent = MIN(max_rsp_size, pCache->data_size - cstate->cStateValue.maxBytesSent); pResponse = pCache->data; memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent); buf->data_size += sent; cstate->cStateValue.maxBytesSent += sent; SDPDBG("Response size : %d sending now : %d bytes sent so far : %d", pCache->data_size, sent, cstate->cStateValue.maxBytesSent); if (cstate->cStateValue.maxBytesSent == pCache->data_size) cstate_size = sdp_set_cstate_pdu(buf, NULL); else cstate_size = sdp_set_cstate_pdu(buf, cstate); } else { status = SDP_INVALID_CSTATE; error("NULL cache buffer and non-NULL continuation state"); } } else { sdp_record_t *rec = sdp_record_find(handle); status = extract_attrs(rec, seq, buf); if (buf->data_size > max_rsp_size) { sdp_cont_state_t newState; memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); newState.timestamp = sdp_cstate_alloc_buf(buf); /* * Reset the buffer size to the maximum expected and * set the sdp_cont_state_t */ SDPDBG("Creating continuation state of size : %d", buf->data_size); buf->data_size = max_rsp_size; newState.cStateValue.maxBytesSent = max_rsp_size; cstate_size = sdp_set_cstate_pdu(buf, &newState); } else { if (buf->data_size == 0) sdp_append_to_buf(buf, NULL, 0); cstate_size = sdp_set_cstate_pdu(buf, NULL); } } /* push header */ buf->data -= sizeof(uint16_t); buf->buf_size += sizeof(uint16_t); done: free(cstate); if (seq) sdp_list_free(seq, free); if (status) return status; /* set attribute list byte count */ bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data); buf->data_size += sizeof(uint16_t); return 0; } /* * combined service search and attribute extraction */ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf) { int status = 0, plen, totscanned; uint8_t *pdata, *pResponse = NULL; unsigned int max; int scanned, rsp_count = 0; sdp_list_t *pattern = NULL, *seq = NULL, *svcList; sdp_cont_state_t *cstate = NULL; short cstate_size = 0; uint8_t dtd = 0; sdp_buf_t tmpbuf; size_t data_left; tmpbuf.data = NULL; pdata = req->buf + sizeof(sdp_pdu_hdr_t); data_left = req->len - sizeof(sdp_pdu_hdr_t); scanned = extract_des(pdata, data_left, &pattern, &dtd, SDP_TYPE_UUID); if (scanned == -1) { status = SDP_INVALID_SYNTAX; goto done; } totscanned = scanned; SDPDBG("Bytes scanned: %d", scanned); pdata += scanned; data_left -= scanned; if (data_left < sizeof(uint16_t)) { status = SDP_INVALID_SYNTAX; goto done; } max = ntohs(bt_get_unaligned((uint16_t *)pdata)); pdata += sizeof(uint16_t); data_left -= sizeof(uint16_t); SDPDBG("Max Attr expected: %d", max); if (data_left < sizeof(sdp_pdu_hdr_t)) { status = SDP_INVALID_SYNTAX; goto done; } /* extract the attribute list */ scanned = extract_des(pdata, data_left, &seq, &dtd, SDP_TYPE_ATTRID); if (scanned == -1) { status = SDP_INVALID_SYNTAX; goto done; } pdata += scanned; data_left -= scanned; totscanned += scanned + sizeof(uint16_t) + 1; plen = ntohs(((sdp_pdu_hdr_t *)(req->buf))->plen); if (plen < totscanned || plen != totscanned + *(uint8_t *)pdata) { status = SDP_INVALID_PDU_SIZE; goto done; } /* * if continuation state exists attempt * to get rsp remainder from cache, else send error */ if (sdp_cstate_get(pdata, data_left, &cstate) < 0) { status = SDP_INVALID_SYNTAX; goto done; } svcList = sdp_get_record_list(); tmpbuf.data = malloc(USHRT_MAX); tmpbuf.data_size = 0; tmpbuf.buf_size = USHRT_MAX; memset(tmpbuf.data, 0, USHRT_MAX); /* * Calculate Attribute size according to MTU * We can send only (MTU - sizeof(sdp_pdu_hdr_t) - sizeof(sdp_cont_state_t)) */ max = MIN(max, req->mtu - sizeof(sdp_pdu_hdr_t) - SDP_CONT_STATE_SIZE - sizeof(uint16_t)); /* pull header for AttributeList byte count */ buf->data += sizeof(uint16_t); buf->buf_size -= sizeof(uint16_t); if (cstate == NULL) { /* no continuation state -> create new response */ sdp_list_t *p; for (p = svcList; p; p = p->next) { sdp_record_t *rec = p->data; if (sdp_match_uuid(pattern, rec->pattern) > 0 && sdp_check_access(rec->handle, &req->device)) { rsp_count++; status = extract_attrs(rec, seq, &tmpbuf); SDPDBG("Response count : %d", rsp_count); SDPDBG("Local PDU size : %d", tmpbuf.data_size); if (status) { SDPDBG("Extract attr from record returns err"); break; } if (buf->data_size + tmpbuf.data_size < buf->buf_size) { /* to be sure no relocations */ sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size); tmpbuf.data_size = 0; memset(tmpbuf.data, 0, USHRT_MAX); } else { error("Relocation needed"); break; } SDPDBG("Net PDU size : %d", buf->data_size); } } if (buf->data_size > max) { sdp_cont_state_t newState; memset((char *)&newState, 0, sizeof(sdp_cont_state_t)); newState.timestamp = sdp_cstate_alloc_buf(buf); /* * Reset the buffer size to the maximum expected and * set the sdp_cont_state_t */ buf->data_size = max; newState.cStateValue.maxBytesSent = max; cstate_size = sdp_set_cstate_pdu(buf, &newState); } else cstate_size = sdp_set_cstate_pdu(buf, NULL); } else { /* continuation State exists -> get from cache */ sdp_buf_t *pCache = sdp_get_cached_rsp(cstate); if (pCache) { uint16_t sent = MIN(max, pCache->data_size - cstate->cStateValue.maxBytesSent); pResponse = pCache->data; memcpy(buf->data, pResponse + cstate->cStateValue.maxBytesSent, sent); buf->data_size += sent; cstate->cStateValue.maxBytesSent += sent; if (cstate->cStateValue.maxBytesSent == pCache->data_size) cstate_size = sdp_set_cstate_pdu(buf, NULL); else cstate_size = sdp_set_cstate_pdu(buf, cstate); } else { status = SDP_INVALID_CSTATE; SDPDBG("Non-null continuation state, but null cache buffer"); } } if (!rsp_count && !cstate) { /* found nothing */ buf->data_size = 0; sdp_append_to_buf(buf, tmpbuf.data, tmpbuf.data_size); sdp_set_cstate_pdu(buf, NULL); } /* push header */ buf->data -= sizeof(uint16_t); buf->buf_size += sizeof(uint16_t); if (!status) { /* set attribute list byte count */ bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data); buf->data_size += sizeof(uint16_t); } done: free(cstate); free(tmpbuf.data); if (pattern) sdp_list_free(pattern, free); if (seq) sdp_list_free(seq, free); return status; } /* * Top level request processor. Calls the appropriate processing * function based on request type. Handles service registration * client requests also. */ static void process_request(sdp_req_t *req) { sdp_pdu_hdr_t *reqhdr = (sdp_pdu_hdr_t *)req->buf; sdp_pdu_hdr_t *rsphdr; sdp_buf_t rsp; uint8_t *buf = malloc(USHRT_MAX); int status = SDP_INVALID_SYNTAX; memset(buf, 0, USHRT_MAX); rsp.data = buf + sizeof(sdp_pdu_hdr_t); rsp.data_size = 0; rsp.buf_size = USHRT_MAX - sizeof(sdp_pdu_hdr_t); rsphdr = (sdp_pdu_hdr_t *)buf; if (ntohs(reqhdr->plen) != req->len - sizeof(sdp_pdu_hdr_t)) { status = SDP_INVALID_PDU_SIZE; goto send_rsp; } switch (reqhdr->pdu_id) { case SDP_SVC_SEARCH_REQ: SDPDBG("Got a svc srch req"); status = service_search_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_SEARCH_RSP; break; case SDP_SVC_ATTR_REQ: SDPDBG("Got a svc attr req"); status = service_attr_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_ATTR_RSP; break; case SDP_SVC_SEARCH_ATTR_REQ: SDPDBG("Got a svc srch attr req"); status = service_search_attr_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_SEARCH_ATTR_RSP; break; /* Following requests are allowed only for local connections */ case SDP_SVC_REGISTER_REQ: SDPDBG("Service register request"); if (req->local) { status = service_register_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_REGISTER_RSP; } break; case SDP_SVC_UPDATE_REQ: SDPDBG("Service update request"); if (req->local) { status = service_update_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_UPDATE_RSP; } break; case SDP_SVC_REMOVE_REQ: SDPDBG("Service removal request"); if (req->local) { status = service_remove_req(req, &rsp); rsphdr->pdu_id = SDP_SVC_REMOVE_RSP; } break; default: error("Unknown PDU ID : 0x%x received", reqhdr->pdu_id); status = SDP_INVALID_SYNTAX; break; } send_rsp: if (status) { rsphdr->pdu_id = SDP_ERROR_RSP; bt_put_unaligned(htons(status), (uint16_t *)rsp.data); rsp.data_size = sizeof(uint16_t); } SDPDBG("Sending rsp. status %d", status); rsphdr->tid = reqhdr->tid; rsphdr->plen = htons(rsp.data_size); /* point back to the real buffer start and set the real rsp length */ rsp.data_size += sizeof(sdp_pdu_hdr_t); rsp.data = buf; /* stream the rsp PDU */ if (send(req->sock, rsp.data, rsp.data_size, 0) < 0) error("send: %s (%d)", strerror(errno), errno); SDPDBG("Bytes Sent : %d", rsp.data_size); free(rsp.data); free(req->buf); } void handle_request(int sk, uint8_t *data, int len) { struct sockaddr_l2 sa; socklen_t size; sdp_req_t req; size = sizeof(sa); if (getpeername(sk, (struct sockaddr *) &sa, &size) < 0) { error("getpeername: %s", strerror(errno)); return; } if (sa.l2_family == AF_BLUETOOTH) { struct l2cap_options lo; memset(&lo, 0, sizeof(lo)); size = sizeof(lo); if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &lo, &size) < 0) { error("getsockopt: %s", strerror(errno)); return; } bacpy(&req.bdaddr, &sa.l2_bdaddr); req.mtu = lo.omtu; req.local = 0; memset(&sa, 0, sizeof(sa)); size = sizeof(sa); if (getsockname(sk, (struct sockaddr *) &sa, &size) < 0) { error("getsockname: %s", strerror(errno)); return; } bacpy(&req.device, &sa.l2_bdaddr); } else { bacpy(&req.device, BDADDR_ANY); bacpy(&req.bdaddr, BDADDR_LOCAL); req.mtu = 2048; req.local = 1; } req.sock = sk; req.buf = data; req.len = len; process_request(&req); } bluez-4.101/src/device.c0000644000000000000000000022246311766125764011751 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "att.h" #include "hcid.h" #include "adapter.h" #include "gattrib.h" #include "attio.h" #include "device.h" #include "dbus-common.h" #include "error.h" #include "glib-helper.h" #include "sdp-client.h" #include "gatt.h" #include "agent.h" #include "sdp-xml.h" #include "storage.h" #include "btio.h" #include "attrib-server.h" #include "attrib/client.h" #define DISCONNECT_TIMER 2 #define DISCOVERY_TIMER 2 #define AUTO_CONNECTION_INTERVAL 5 /* Next connection attempt */ /* When all services should trust a remote device */ #define GLOBAL_TRUST "[all]" #define APPEARANCE_CHR_UUID 0x2a01 struct btd_disconnect_data { guint id; disconnect_watch watch; void *user_data; GDestroyNotify destroy; }; struct bonding_req { DBusConnection *conn; DBusMessage *msg; guint listener_id; struct btd_device *device; }; struct authentication_req { auth_type_t type; void *cb; struct agent *agent; struct btd_device *device; uint32_t passkey; char *pincode; gboolean secure; }; struct browse_req { DBusConnection *conn; DBusMessage *msg; struct btd_device *device; GSList *match_uuids; GSList *profiles_added; GSList *profiles_removed; sdp_list_t *records; int search_uuid; int reconnect_attempt; guint listener_id; }; struct attio_data { guint id; attio_connect_cb cfunc; attio_disconnect_cb dcfunc; gpointer user_data; }; typedef void (*attio_error_cb) (const GError *gerr, gpointer user_data); typedef void (*attio_success_cb) (gpointer user_data); struct att_callbacks { attio_error_cb error; /* Callback for error */ attio_success_cb success; /* Callback for success */ gpointer user_data; }; struct btd_device { bdaddr_t bdaddr; uint8_t bdaddr_type; gchar *path; char name[MAX_NAME_LENGTH + 1]; char *alias; uint16_t vendor_src; uint16_t vendor; uint16_t product; uint16_t version; struct btd_adapter *adapter; GSList *uuids; GSList *services; /* Primary services path */ GSList *primaries; /* List of primary services */ GSList *drivers; /* List of device drivers */ GSList *watches; /* List of disconnect_data */ gboolean temporary; struct agent *agent; guint disconn_timer; guint discov_timer; struct browse_req *browse; /* service discover request */ struct bonding_req *bonding; struct authentication_req *authr; /* authentication request */ GSList *disconnects; /* disconnects message */ GAttrib *attrib; GSList *attios; GSList *attios_offline; guint attachid; /* Attrib server attach */ guint auto_id; /* Auto connect source id */ gboolean connected; sdp_list_t *tmp_records; gboolean trusted; gboolean paired; gboolean blocked; gboolean bonded; gboolean auto_connect; gboolean authorizing; gint ref; GIOChannel *att_io; guint cleanup_id; }; static uint16_t uuid_list[] = { L2CAP_UUID, PNP_INFO_SVCLASS_ID, PUBLIC_BROWSE_GROUP, 0 }; static GSList *device_drivers = NULL; static void browse_request_free(struct browse_req *req) { if (req->listener_id) g_dbus_remove_watch(req->conn, req->listener_id); if (req->msg) dbus_message_unref(req->msg); if (req->conn) dbus_connection_unref(req->conn); if (req->device) btd_device_unref(req->device); g_slist_free_full(req->profiles_added, g_free); g_slist_free(req->profiles_removed); if (req->records) sdp_list_free(req->records, (sdp_free_func_t) sdp_record_free); g_free(req); } static void att_cleanup(struct btd_device *device) { if (device->attachid) { attrib_channel_detach(device->attrib, device->attachid); device->attachid = 0; } if (device->cleanup_id) { g_source_remove(device->cleanup_id); device->cleanup_id = 0; } if (device->att_io) { g_io_channel_shutdown(device->att_io, FALSE, NULL); g_io_channel_unref(device->att_io); device->att_io = NULL; } if (device->attrib) { g_attrib_unref(device->attrib); device->attrib = NULL; } } static void browse_request_cancel(struct browse_req *req) { struct btd_device *device = req->device; struct btd_adapter *adapter = device->adapter; bdaddr_t src; if (device_is_creating(device, NULL)) device_set_temporary(device, TRUE); adapter_get_address(adapter, &src); bt_cancel_discovery(&src, &device->bdaddr); att_cleanup(device); device->browse = NULL; browse_request_free(req); } static void device_free(gpointer user_data) { struct btd_device *device = user_data; struct btd_adapter *adapter = device->adapter; struct agent *agent = adapter_get_agent(adapter); if (device->agent) agent_free(device->agent); if (agent && (agent_is_busy(agent, device) || agent_is_busy(agent, device->authr))) agent_cancel(agent); g_slist_free_full(device->services, g_free); g_slist_free_full(device->uuids, g_free); g_slist_free_full(device->primaries, g_free); g_slist_free_full(device->attios, g_free); g_slist_free_full(device->attios_offline, g_free); att_cleanup(device); if (device->tmp_records) sdp_list_free(device->tmp_records, (sdp_free_func_t) sdp_record_free); if (device->disconn_timer) g_source_remove(device->disconn_timer); if (device->discov_timer) g_source_remove(device->discov_timer); if (device->auto_id) g_source_remove(device->auto_id); DBG("%p", device); if (device->authr) g_free(device->authr->pincode); g_free(device->authr); g_free(device->path); g_free(device->alias); g_free(device); } gboolean device_is_bredr(struct btd_device *device) { return (device->bdaddr_type == BDADDR_BREDR); } gboolean device_is_le(struct btd_device *device) { return (device->bdaddr_type != BDADDR_BREDR); } gboolean device_is_paired(struct btd_device *device) { return device->paired; } gboolean device_is_bonded(struct btd_device *device) { return device->bonded; } gboolean device_is_trusted(struct btd_device *device) { return device->trusted; } static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct btd_device *device = user_data; struct btd_adapter *adapter = device->adapter; DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; bdaddr_t src; char name[MAX_NAME_LENGTH + 1], srcaddr[18], dstaddr[18]; char **str; const char *ptr, *icon = NULL; dbus_bool_t boolean; uint32_t class; uint16_t app; int i; GSList *l; ba2str(&device->bdaddr, dstaddr); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); /* Address */ ptr = dstaddr; dict_append_entry(&dict, "Address", DBUS_TYPE_STRING, &ptr); /* Name */ ptr = NULL; memset(name, 0, sizeof(name)); adapter_get_address(adapter, &src); ba2str(&src, srcaddr); ptr = device->name; dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ptr); /* Alias (fallback to name or address) */ if (device->alias != NULL) ptr = device->alias; else if (strlen(ptr) == 0) { g_strdelimit(dstaddr, ":", '-'); ptr = dstaddr; } dict_append_entry(&dict, "Alias", DBUS_TYPE_STRING, &ptr); /* Class */ if (read_remote_class(&src, &device->bdaddr, &class) == 0) { icon = class_to_icon(class); dict_append_entry(&dict, "Class", DBUS_TYPE_UINT32, &class); } else if (read_remote_appearance(&src, &device->bdaddr, device->bdaddr_type, &app) == 0) /* Appearance */ icon = gap_appearance_to_icon(app); dict_append_entry(&dict, "Icon", DBUS_TYPE_STRING, &icon); /* Vendor */ if (device->vendor) dict_append_entry(&dict, "Vendor", DBUS_TYPE_UINT16, &device->vendor); /* Vendor Source*/ if (device->vendor_src) dict_append_entry(&dict, "VendorSource", DBUS_TYPE_UINT16, &device->vendor_src); /* Product */ if (device->product) dict_append_entry(&dict, "Product", DBUS_TYPE_UINT16, &device->product); /* Version */ if (device->version) dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16, &device->version); /* Paired */ boolean = device_is_paired(device); dict_append_entry(&dict, "Paired", DBUS_TYPE_BOOLEAN, &boolean); /* Trusted */ boolean = device_is_trusted(device); dict_append_entry(&dict, "Trusted", DBUS_TYPE_BOOLEAN, &boolean); /* Blocked */ boolean = device->blocked; dict_append_entry(&dict, "Blocked", DBUS_TYPE_BOOLEAN, &boolean); /* Connected */ dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &device->connected); /* UUIDs */ str = g_new0(char *, g_slist_length(device->uuids) + 1); for (i = 0, l = device->uuids; l; l = l->next, i++) str[i] = l->data; dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &str, i); g_free(str); /* Services */ str = g_new0(char *, g_slist_length(device->services) + 1); for (i = 0, l = device->services; l; l = l->next, i++) str[i] = l->data; dict_append_array(&dict, "Services", DBUS_TYPE_OBJECT_PATH, &str, i); g_free(str); /* Adapter */ ptr = adapter_get_path(adapter); dict_append_entry(&dict, "Adapter", DBUS_TYPE_OBJECT_PATH, &ptr); dbus_message_iter_close_container(&iter, &dict); return reply; } static DBusMessage *set_alias(DBusConnection *conn, DBusMessage *msg, const char *alias, void *data) { struct btd_device *device = data; struct btd_adapter *adapter = device->adapter; char srcaddr[18], dstaddr[18]; bdaddr_t src; int err; /* No change */ if ((device->alias == NULL && g_str_equal(alias, "")) || g_strcmp0(device->alias, alias) == 0) return dbus_message_new_method_return(msg); adapter_get_address(adapter, &src); ba2str(&src, srcaddr); ba2str(&device->bdaddr, dstaddr); /* Remove alias if empty string */ err = write_device_alias(srcaddr, dstaddr, g_str_equal(alias, "") ? NULL : alias); if (err < 0) return btd_error_failed(msg, strerror(-err)); g_free(device->alias); device->alias = g_str_equal(alias, "") ? NULL : g_strdup(alias); emit_property_changed(conn, dbus_message_get_path(msg), DEVICE_INTERFACE, "Alias", DBUS_TYPE_STRING, &alias); return dbus_message_new_method_return(msg); } static DBusMessage *set_trust(DBusConnection *conn, DBusMessage *msg, gboolean value, void *data) { struct btd_device *device = data; struct btd_adapter *adapter = device->adapter; char srcaddr[18], dstaddr[18]; bdaddr_t src; int err; if (device->trusted == value) return dbus_message_new_method_return(msg); adapter_get_address(adapter, &src); ba2str(&src, srcaddr); ba2str(&device->bdaddr, dstaddr); err = write_trust(srcaddr, dstaddr, GLOBAL_TRUST, value); if (err < 0) return btd_error_failed(msg, strerror(-err)); device->trusted = value; emit_property_changed(conn, dbus_message_get_path(msg), DEVICE_INTERFACE, "Trusted", DBUS_TYPE_BOOLEAN, &value); return dbus_message_new_method_return(msg); } static void driver_remove(struct btd_device_driver *driver, struct btd_device *device) { driver->remove(device); device->drivers = g_slist_remove(device->drivers, driver); } static gboolean do_disconnect(gpointer user_data) { struct btd_device *device = user_data; device->disconn_timer = 0; btd_adapter_disconnect_device(device->adapter, &device->bdaddr, device->bdaddr_type); return FALSE; } int device_block(DBusConnection *conn, struct btd_device *device, gboolean update_only) { int err = 0; bdaddr_t src; if (device->blocked) return 0; if (device->connected) do_disconnect(device); g_slist_foreach(device->drivers, (GFunc) driver_remove, device); if (!update_only) err = btd_adapter_block_address(device->adapter, &device->bdaddr, device->bdaddr_type); if (err < 0) return err; device->blocked = TRUE; adapter_get_address(device->adapter, &src); err = write_blocked(&src, &device->bdaddr, TRUE); if (err < 0) error("write_blocked(): %s (%d)", strerror(-err), -err); device_set_temporary(device, FALSE); emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Blocked", DBUS_TYPE_BOOLEAN, &device->blocked); return 0; } int device_unblock(DBusConnection *conn, struct btd_device *device, gboolean silent, gboolean update_only) { int err = 0; bdaddr_t src; if (!device->blocked) return 0; if (!update_only) err = btd_adapter_unblock_address(device->adapter, &device->bdaddr, device->bdaddr_type); if (err < 0) return err; device->blocked = FALSE; adapter_get_address(device->adapter, &src); err = write_blocked(&src, &device->bdaddr, FALSE); if (err < 0) error("write_blocked(): %s (%d)", strerror(-err), -err); if (!silent) { emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Blocked", DBUS_TYPE_BOOLEAN, &device->blocked); device_probe_drivers(device, device->uuids); } return 0; } static DBusMessage *set_blocked(DBusConnection *conn, DBusMessage *msg, gboolean value, void *data) { struct btd_device *device = data; int err; if (value) err = device_block(conn, device, FALSE); else err = device_unblock(conn, device, FALSE, FALSE); switch (-err) { case 0: return dbus_message_new_method_return(msg); case EINVAL: return btd_error_failed(msg, "Kernel lacks blacklist support"); default: return btd_error_failed(msg, strerror(-err)); } } static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter; DBusMessageIter sub; const char *property; if (!dbus_message_iter_init(msg, &iter)) return btd_error_invalid_args(msg); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&iter, &property); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) return btd_error_invalid_args(msg); dbus_message_iter_recurse(&iter, &sub); if (g_str_equal("Trusted", property)) { dbus_bool_t value; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &value); return set_trust(conn, msg, value, data); } else if (g_str_equal("Alias", property)) { const char *alias; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &alias); return set_alias(conn, msg, alias, data); } else if (g_str_equal("Blocked", property)) { dbus_bool_t value; if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&sub, &value); return set_blocked(conn, msg, value, data); } return btd_error_invalid_args(msg); } static void discover_services_req_exit(DBusConnection *conn, void *user_data) { struct browse_req *req = user_data; DBG("DiscoverServices requestor exited"); browse_request_cancel(req); } static DBusMessage *discover_services(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct btd_device *device = user_data; const char *pattern; int err; if (device->browse) return btd_error_in_progress(msg); if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern, DBUS_TYPE_INVALID) == FALSE) return btd_error_invalid_args(msg); if (strlen(pattern) == 0) { err = device_browse_sdp(device, conn, msg, NULL, FALSE); if (err < 0) goto fail; } else { uuid_t uuid; if (bt_string2uuid(&uuid, pattern) < 0) return btd_error_invalid_args(msg); sdp_uuid128_to_uuid(&uuid); err = device_browse_sdp(device, conn, msg, &uuid, FALSE); if (err < 0) goto fail; } return NULL; fail: return btd_error_failed(msg, strerror(-err)); } static const char *browse_request_get_requestor(struct browse_req *req) { if (!req->msg) return NULL; return dbus_message_get_sender(req->msg); } static void iter_append_record(DBusMessageIter *dict, uint32_t handle, const char *record) { DBusMessageIter entry; dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); dbus_message_iter_append_basic(&entry, DBUS_TYPE_UINT32, &handle); dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &record); dbus_message_iter_close_container(dict, &entry); } static void discover_services_reply(struct browse_req *req, int err, sdp_list_t *recs) { DBusMessage *reply; DBusMessageIter iter, dict; sdp_list_t *seq; if (err) { const char *err_if; if (err == -EHOSTDOWN) err_if = ERROR_INTERFACE ".ConnectionAttemptFailed"; else err_if = ERROR_INTERFACE ".Failed"; reply = dbus_message_new_error(req->msg, err_if, strerror(-err)); g_dbus_send_message(req->conn, reply); return; } reply = dbus_message_new_method_return(req->msg); if (!reply) return; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_UINT32_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); for (seq = recs; seq; seq = seq->next) { sdp_record_t *rec = (sdp_record_t *) seq->data; GString *result; if (!rec) break; result = g_string_new(NULL); convert_sdp_record_to_xml(rec, result, (void *) g_string_append); if (result->len) iter_append_record(&dict, rec->handle, result->str); g_string_free(result, TRUE); } dbus_message_iter_close_container(&iter, &dict); g_dbus_send_message(req->conn, reply); } static DBusMessage *cancel_discover(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct btd_device *device = user_data; const char *sender = dbus_message_get_sender(msg); const char *requestor; if (!device->browse) return btd_error_does_not_exist(msg); if (!dbus_message_is_method_call(device->browse->msg, DEVICE_INTERFACE, "DiscoverServices")) return btd_error_not_authorized(msg); requestor = browse_request_get_requestor(device->browse); /* only the discover requestor can cancel the inquiry process */ if (!requestor || !g_str_equal(requestor, sender)) return btd_error_not_authorized(msg); discover_services_reply(device->browse, -ECANCELED, NULL); browse_request_cancel(device->browse); return dbus_message_new_method_return(msg); } static void bonding_request_cancel(struct bonding_req *bonding) { struct btd_device *device = bonding->device; struct btd_adapter *adapter = device->adapter; adapter_cancel_bonding(adapter, &device->bdaddr); } void device_request_disconnect(struct btd_device *device, DBusMessage *msg) { DBusConnection *conn = get_dbus_connection(); if (device->bonding) bonding_request_cancel(device->bonding); if (device->browse) { discover_services_reply(device->browse, -ECANCELED, NULL); browse_request_cancel(device->browse); } if (msg) device->disconnects = g_slist_append(device->disconnects, dbus_message_ref(msg)); if (device->disconn_timer) return; while (device->watches) { struct btd_disconnect_data *data = device->watches->data; if (data->watch) /* temporary is set if device is going to be removed */ data->watch(device, device->temporary, data->user_data); /* Check if the watch has been removed by callback function */ if (!g_slist_find(device->watches, data)) continue; device->watches = g_slist_remove(device->watches, data); g_free(data); } device->disconn_timer = g_timeout_add_seconds(DISCONNECT_TIMER, do_disconnect, device); g_dbus_emit_signal(conn, device->path, DEVICE_INTERFACE, "DisconnectRequested", DBUS_TYPE_INVALID); } static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct btd_device *device = user_data; if (!device->connected) return btd_error_not_connected(msg); device_request_disconnect(device, msg); return NULL; } static const GDBusMethodTable device_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), get_properties) }, { GDBUS_METHOD("SetProperty", GDBUS_ARGS({ "name", "s" }, { "value", "v" }), NULL, set_property) }, { GDBUS_ASYNC_METHOD("DiscoverServices", GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "services", "a{us}" }), discover_services) }, { GDBUS_METHOD("CancelDiscovery", NULL, NULL, cancel_discover) }, { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, disconnect) }, { } }; static const GDBusSignalTable device_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { GDBUS_SIGNAL("DisconnectRequested", NULL) }, { } }; gboolean device_is_connected(struct btd_device *device) { return device->connected; } void device_add_connection(struct btd_device *device, DBusConnection *conn) { if (device->connected) { char addr[18]; ba2str(&device->bdaddr, addr); error("Device %s is already connected", addr); return; } device->connected = TRUE; emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &device->connected); } void device_remove_connection(struct btd_device *device, DBusConnection *conn) { if (!device->connected) { char addr[18]; ba2str(&device->bdaddr, addr); error("Device %s isn't connected", addr); return; } device->connected = FALSE; if (device->disconn_timer > 0) { g_source_remove(device->disconn_timer); device->disconn_timer = 0; } while (device->disconnects) { DBusMessage *msg = device->disconnects->data; g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID); device->disconnects = g_slist_remove(device->disconnects, msg); } if (device_is_paired(device) && !device_is_bonded(device)) device_set_paired(device, FALSE); emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Connected", DBUS_TYPE_BOOLEAN, &device->connected); } guint device_add_disconnect_watch(struct btd_device *device, disconnect_watch watch, void *user_data, GDestroyNotify destroy) { struct btd_disconnect_data *data; static guint id = 0; data = g_new0(struct btd_disconnect_data, 1); data->id = ++id; data->watch = watch; data->user_data = user_data; data->destroy = destroy; device->watches = g_slist_append(device->watches, data); return data->id; } void device_remove_disconnect_watch(struct btd_device *device, guint id) { GSList *l; for (l = device->watches; l; l = l->next) { struct btd_disconnect_data *data = l->data; if (data->id == id) { device->watches = g_slist_remove(device->watches, data); if (data->destroy) data->destroy(data->user_data); g_free(data); return; } } } static void device_set_vendor(struct btd_device *device, uint16_t value) { DBusConnection *conn = get_dbus_connection(); if (device->vendor == value) return; device->vendor = value; emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Vendor", DBUS_TYPE_UINT16, &value); } static void device_set_vendor_src(struct btd_device *device, uint16_t value) { DBusConnection *conn = get_dbus_connection(); if (device->vendor_src == value) return; device->vendor_src = value; emit_property_changed(conn, device->path, DEVICE_INTERFACE, "VendorSource", DBUS_TYPE_UINT16, &value); } static void device_set_product(struct btd_device *device, uint16_t value) { DBusConnection *conn = get_dbus_connection(); if (device->product == value) return; device->product = value; emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Product", DBUS_TYPE_UINT16, &value); } static void device_set_version(struct btd_device *device, uint16_t value) { DBusConnection *conn = get_dbus_connection(); if (device->version == value) return; device->version = value; emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Version", DBUS_TYPE_UINT16, &value); } struct btd_device *device_create(DBusConnection *conn, struct btd_adapter *adapter, const gchar *address, uint8_t bdaddr_type) { gchar *address_up; struct btd_device *device; const gchar *adapter_path = adapter_get_path(adapter); bdaddr_t src; char srcaddr[18], alias[MAX_NAME_LENGTH + 1]; uint16_t vendor, product, version; device = g_try_malloc0(sizeof(struct btd_device)); if (device == NULL) return NULL; address_up = g_ascii_strup(address, -1); device->path = g_strdup_printf("%s/dev_%s", adapter_path, address_up); g_strdelimit(device->path, ":", '_'); g_free(address_up); DBG("Creating device %s", device->path); if (g_dbus_register_interface(conn, device->path, DEVICE_INTERFACE, device_methods, device_signals, NULL, device, device_free) == FALSE) { device_free(device); return NULL; } str2ba(address, &device->bdaddr); device->adapter = adapter; device->bdaddr_type = bdaddr_type; adapter_get_address(adapter, &src); ba2str(&src, srcaddr); read_device_name(srcaddr, address, device->name); if (read_device_alias(srcaddr, address, alias, sizeof(alias)) == 0) device->alias = g_strdup(alias); device->trusted = read_trust(&src, address, GLOBAL_TRUST); if (read_blocked(&src, &device->bdaddr)) device_block(conn, device, FALSE); if (read_link_key(&src, &device->bdaddr, NULL, NULL) == 0) { device_set_paired(device, TRUE); device_set_bonded(device, TRUE); } if (device_is_le(device) && has_longtermkeys(&src, &device->bdaddr, device->bdaddr_type)) { device_set_paired(device, TRUE); device_set_bonded(device, TRUE); } if (read_device_id(srcaddr, address, NULL, &vendor, &product, &version) == 0) { device_set_vendor(device, vendor); device_set_product(device, product); device_set_version(device, version); } return btd_device_ref(device); } void device_set_name(struct btd_device *device, const char *name) { DBusConnection *conn = get_dbus_connection(); if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0) return; strncpy(device->name, name, MAX_NAME_LENGTH); emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Name", DBUS_TYPE_STRING, &name); if (device->alias != NULL) return; emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Alias", DBUS_TYPE_STRING, &name); } void device_get_name(struct btd_device *device, char *name, size_t len) { strncpy(name, device->name, len); } uint16_t btd_device_get_vendor(struct btd_device *device) { return device->vendor; } uint16_t btd_device_get_vendor_src(struct btd_device *device) { return device->vendor_src; } uint16_t btd_device_get_product(struct btd_device *device) { return device->product; } uint16_t btd_device_get_version(struct btd_device *device) { return device->version; } static void device_remove_stored(struct btd_device *device) { bdaddr_t src; char key[20]; DBusConnection *conn = get_dbus_connection(); adapter_get_address(device->adapter, &src); ba2str(&device->bdaddr, key); /* key: address only */ delete_entry(&src, "profiles", key); delete_entry(&src, "trusts", key); if (device_is_bonded(device)) { delete_entry(&src, "linkkeys", key); delete_entry(&src, "aliases", key); /* key: address#type */ sprintf(&key[17], "#%hhu", device->bdaddr_type); delete_entry(&src, "longtermkeys", key); device_set_bonded(device, FALSE); device->paired = FALSE; btd_adapter_remove_bonding(device->adapter, &device->bdaddr, device->bdaddr_type); } delete_all_records(&src, &device->bdaddr); delete_device_service(&src, &device->bdaddr, device->bdaddr_type); if (device->blocked) device_unblock(conn, device, TRUE, FALSE); } void device_remove(struct btd_device *device, gboolean remove_stored) { DBG("Removing device %s", device->path); if (device->agent) agent_free(device->agent); if (device->bonding) { uint8_t status; if (device->connected) status = HCI_OE_USER_ENDED_CONNECTION; else status = HCI_PAGE_TIMEOUT; device_cancel_bonding(device, status); } if (device->browse) { discover_services_reply(device->browse, -ECANCELED, NULL); browse_request_cancel(device->browse); } if (device->connected) do_disconnect(device); if (remove_stored) device_remove_stored(device); g_slist_foreach(device->drivers, (GFunc) driver_remove, device); g_slist_free(device->drivers); device->drivers = NULL; attrib_client_unregister(device->services); btd_device_unref(device); } gint device_address_cmp(struct btd_device *device, const gchar *address) { char addr[18]; ba2str(&device->bdaddr, addr); return strcasecmp(addr, address); } static gboolean record_has_uuid(const sdp_record_t *rec, const char *profile_uuid) { sdp_list_t *pat; for (pat = rec->pattern; pat != NULL; pat = pat->next) { char *uuid; int ret; uuid = bt_uuid2string(pat->data); if (!uuid) continue; ret = strcasecmp(uuid, profile_uuid); g_free(uuid); if (ret == 0) return TRUE; } return FALSE; } static GSList *device_match_pattern(struct btd_device *device, const char *match_uuid, GSList *profiles) { GSList *l, *uuids = NULL; for (l = profiles; l; l = l->next) { char *profile_uuid = l->data; const sdp_record_t *rec; rec = btd_device_get_record(device, profile_uuid); if (!rec) continue; if (record_has_uuid(rec, match_uuid)) uuids = g_slist_append(uuids, profile_uuid); } return uuids; } static GSList *device_match_driver(struct btd_device *device, struct btd_device_driver *driver, GSList *profiles) { const char **uuid; GSList *uuids = NULL; for (uuid = driver->uuids; *uuid; uuid++) { GSList *match; /* skip duplicated uuids */ if (g_slist_find_custom(uuids, *uuid, (GCompareFunc) strcasecmp)) continue; /* match profile driver */ match = g_slist_find_custom(profiles, *uuid, (GCompareFunc) strcasecmp); if (match) { uuids = g_slist_append(uuids, match->data); continue; } /* match pattern driver */ match = device_match_pattern(device, *uuid, profiles); uuids = g_slist_concat(uuids, match); } return uuids; } void device_probe_drivers(struct btd_device *device, GSList *profiles) { GSList *list; char addr[18]; int err; ba2str(&device->bdaddr, addr); if (device->blocked) { DBG("Skipping drivers for blocked device %s", addr); goto add_uuids; } DBG("Probing drivers for %s", addr); for (list = device_drivers; list; list = list->next) { struct btd_device_driver *driver = list->data; GSList *probe_uuids; probe_uuids = device_match_driver(device, driver, profiles); if (!probe_uuids) continue; err = driver->probe(device, probe_uuids); if (err < 0) { error("%s driver probe failed for device %s", driver->name, addr); g_slist_free(probe_uuids); continue; } device->drivers = g_slist_append(device->drivers, driver); g_slist_free(probe_uuids); } add_uuids: for (list = profiles; list; list = list->next) { GSList *l = g_slist_find_custom(device->uuids, list->data, (GCompareFunc) strcasecmp); if (l) continue; device->uuids = g_slist_insert_sorted(device->uuids, g_strdup(list->data), (GCompareFunc) strcasecmp); } } static void device_remove_drivers(struct btd_device *device, GSList *uuids) { struct btd_adapter *adapter = device_get_adapter(device); GSList *list, *next; char srcaddr[18], dstaddr[18]; bdaddr_t src; sdp_list_t *records; adapter_get_address(adapter, &src); ba2str(&src, srcaddr); ba2str(&device->bdaddr, dstaddr); records = read_records(&src, &device->bdaddr); DBG("Removing drivers for %s", dstaddr); for (list = device->drivers; list; list = next) { struct btd_device_driver *driver = list->data; const char **uuid; next = list->next; for (uuid = driver->uuids; *uuid; uuid++) { if (!g_slist_find_custom(uuids, *uuid, (GCompareFunc) strcasecmp)) continue; DBG("UUID %s was removed from device %s", *uuid, dstaddr); driver->remove(device); device->drivers = g_slist_remove(device->drivers, driver); break; } } for (list = uuids; list; list = list->next) { sdp_record_t *rec; device->uuids = g_slist_remove(device->uuids, list->data); rec = find_record_in_list(records, list->data); if (!rec) continue; delete_record(srcaddr, dstaddr, rec->handle); records = sdp_list_remove(records, rec); sdp_record_free(rec); } if (records) sdp_list_free(records, (sdp_free_func_t) sdp_record_free); } static void services_changed(struct btd_device *device) { DBusConnection *conn = get_dbus_connection(); char **uuids; GSList *l; int i; uuids = g_new0(char *, g_slist_length(device->uuids) + 1); for (i = 0, l = device->uuids; l; l = l->next, i++) uuids[i] = l->data; emit_array_property_changed(conn, device->path, DEVICE_INTERFACE, "UUIDs", DBUS_TYPE_STRING, &uuids, i); g_free(uuids); } static int rec_cmp(const void *a, const void *b) { const sdp_record_t *r1 = a; const sdp_record_t *r2 = b; return r1->handle - r2->handle; } static void update_services(struct browse_req *req, sdp_list_t *recs) { struct btd_device *device = req->device; struct btd_adapter *adapter = device_get_adapter(device); sdp_list_t *seq; char srcaddr[18], dstaddr[18]; bdaddr_t src; adapter_get_address(adapter, &src); ba2str(&src, srcaddr); ba2str(&device->bdaddr, dstaddr); for (seq = recs; seq; seq = seq->next) { sdp_record_t *rec = (sdp_record_t *) seq->data; sdp_list_t *svcclass = NULL; gchar *profile_uuid; GSList *l; if (!rec) break; if (sdp_get_service_classes(rec, &svcclass) < 0) continue; /* Check for empty service classes list */ if (svcclass == NULL) { DBG("Skipping record with no service classes"); continue; } /* Extract the first element and skip the remainning */ profile_uuid = bt_uuid2string(svcclass->data); if (!profile_uuid) { sdp_list_free(svcclass, free); continue; } if (!strcasecmp(profile_uuid, PNP_UUID)) { uint16_t source, vendor, product, version; sdp_data_t *pdlist; pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID_SOURCE); source = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID); vendor = pdlist ? pdlist->val.uint16 : 0x0000; device_set_vendor(device, vendor); pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID); product = pdlist ? pdlist->val.uint16 : 0x0000; device_set_product(device, product); pdlist = sdp_data_get(rec, SDP_ATTR_VERSION); version = pdlist ? pdlist->val.uint16 : 0x0000; device_set_version(device, version); if (source || vendor || product || version) store_device_id(srcaddr, dstaddr, source, vendor, product, version); } /* Check for duplicates */ if (sdp_list_find(req->records, rec, rec_cmp)) { g_free(profile_uuid); sdp_list_free(svcclass, free); continue; } store_record(srcaddr, dstaddr, rec); /* Copy record */ req->records = sdp_list_append(req->records, sdp_copy_record(rec)); l = g_slist_find_custom(device->uuids, profile_uuid, (GCompareFunc) strcmp); if (!l) req->profiles_added = g_slist_append(req->profiles_added, profile_uuid); else { req->profiles_removed = g_slist_remove(req->profiles_removed, l->data); g_free(profile_uuid); } sdp_list_free(svcclass, free); } } static void store_profiles(struct btd_device *device) { struct btd_adapter *adapter = device->adapter; bdaddr_t src; char *str; adapter_get_address(adapter, &src); if (!device->uuids) { write_device_profiles(&src, &device->bdaddr, ""); return; } str = bt_list2string(device->uuids); write_device_profiles(&src, &device->bdaddr, str); g_free(str); } static void create_device_reply(struct btd_device *device, struct browse_req *req) { DBusMessage *reply; reply = dbus_message_new_method_return(req->msg); if (!reply) return; dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &device->path, DBUS_TYPE_INVALID); g_dbus_send_message(req->conn, reply); } GSList *device_services_from_record(struct btd_device *device, GSList *profiles) { GSList *l, *prim_list = NULL; char *att_uuid; uuid_t proto_uuid; sdp_uuid16_create(&proto_uuid, ATT_UUID); att_uuid = bt_uuid2string(&proto_uuid); for (l = profiles; l; l = l->next) { const char *profile_uuid = l->data; const sdp_record_t *rec; struct gatt_primary *prim; uint16_t start = 0, end = 0, psm = 0; uuid_t prim_uuid; rec = btd_device_get_record(device, profile_uuid); if (!rec) continue; if (!record_has_uuid(rec, att_uuid)) continue; if (!gatt_parse_record(rec, &prim_uuid, &psm, &start, &end)) continue; prim = g_new0(struct gatt_primary, 1); prim->range.start = start; prim->range.end = end; sdp_uuid2strn(&prim_uuid, prim->uuid, sizeof(prim->uuid)); prim_list = g_slist_append(prim_list, prim); } g_free(att_uuid); return prim_list; } static void search_cb(sdp_list_t *recs, int err, gpointer user_data) { struct browse_req *req = user_data; struct btd_device *device = req->device; char addr[18]; ba2str(&device->bdaddr, addr); if (err < 0) { error("%s: error updating services: %s (%d)", addr, strerror(-err), -err); goto send_reply; } update_services(req, recs); if (device->tmp_records) sdp_list_free(device->tmp_records, (sdp_free_func_t) sdp_record_free); device->tmp_records = req->records; req->records = NULL; if (!req->profiles_added && !req->profiles_removed) { DBG("%s: No service update", addr); goto send_reply; } /* Probe matching drivers for services added */ if (req->profiles_added) { GSList *list; list = device_services_from_record(device, req->profiles_added); if (list) device_register_services(req->conn, device, list, ATT_PSM); device_probe_drivers(device, req->profiles_added); } /* Remove drivers for services removed */ if (req->profiles_removed) device_remove_drivers(device, req->profiles_removed); /* Propagate services changes */ services_changed(req->device); send_reply: if (!req->msg) goto cleanup; if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "DiscoverServices")) discover_services_reply(req, err, device->tmp_records); else if (dbus_message_is_method_call(req->msg, ADAPTER_INTERFACE, "CreatePairedDevice")) create_device_reply(device, req); else if (dbus_message_is_method_call(req->msg, ADAPTER_INTERFACE, "CreateDevice")) { if (err < 0) { DBusMessage *reply; reply = btd_error_failed(req->msg, strerror(-err)); g_dbus_send_message(req->conn, reply); goto cleanup; } create_device_reply(device, req); device_set_temporary(device, FALSE); } cleanup: if (!device->temporary) { bdaddr_t sba, dba; adapter_get_address(device->adapter, &sba); device_get_address(device, &dba, NULL); store_profiles(device); } device->browse = NULL; browse_request_free(req); } static void browse_cb(sdp_list_t *recs, int err, gpointer user_data) { struct browse_req *req = user_data; struct btd_device *device = req->device; struct btd_adapter *adapter = device->adapter; bdaddr_t src; uuid_t uuid; /* If we have a valid response and req->search_uuid == 2, then L2CAP * UUID & PNP searching was successful -- we are done */ if (err < 0 || (req->search_uuid == 2 && req->records)) { if (err == -ECONNRESET && req->reconnect_attempt < 1) { req->search_uuid--; req->reconnect_attempt++; } else goto done; } update_services(req, recs); adapter_get_address(adapter, &src); /* Search for mandatory uuids */ if (uuid_list[req->search_uuid]) { sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]); bt_search_service(&src, &device->bdaddr, &uuid, browse_cb, user_data, NULL); return; } done: search_cb(recs, err, user_data); } static void init_browse(struct browse_req *req, gboolean reverse) { GSList *l; /* If we are doing reverse-SDP don't try to detect removed profiles * since some devices hide their service records while they are * connected */ if (reverse) return; for (l = req->device->uuids; l; l = l->next) req->profiles_removed = g_slist_append(req->profiles_removed, l->data); } static char *primary_list_to_string(GSList *primary_list) { GString *services; GSList *l; services = g_string_new(NULL); for (l = primary_list; l; l = l->next) { struct gatt_primary *primary = l->data; char service[64]; memset(service, 0, sizeof(service)); snprintf(service, sizeof(service), "%04X#%04X#%s ", primary->range.start, primary->range.end, primary->uuid); services = g_string_append(services, service); } return g_string_free(services, FALSE); } static void store_services(struct btd_device *device) { struct btd_adapter *adapter = device->adapter; bdaddr_t dba, sba; char *str = primary_list_to_string(device->primaries); adapter_get_address(adapter, &sba); device_get_address(device, &dba, NULL); write_device_services(&sba, &dba, device->bdaddr_type, str); g_free(str); } static void attio_connected(gpointer data, gpointer user_data) { struct attio_data *attio = data; GAttrib *attrib = user_data; if (attio->cfunc) attio->cfunc(attrib, attio->user_data); } static void attio_disconnected(gpointer data, gpointer user_data) { struct attio_data *attio = data; if (attio->dcfunc) attio->dcfunc(attio->user_data); } static void att_connect_dispatched(gpointer user_data) { struct btd_device *device = user_data; device->auto_id = 0; } static gboolean att_connect(gpointer user_data); static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct btd_device *device = user_data; int sock, err = 0; socklen_t len; if (device->browse) goto done; sock = g_io_channel_unix_get_fd(io); len = sizeof(err); getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len); g_slist_foreach(device->attios, attio_disconnected, NULL); if (device->auto_connect == FALSE || err != ETIMEDOUT) goto done; device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE, AUTO_CONNECTION_INTERVAL, att_connect, device, att_connect_dispatched); done: att_cleanup(device); return FALSE; } static void appearance_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct btd_device *device = user_data; struct btd_adapter *adapter = device->adapter; struct att_data_list *list = NULL; uint16_t app; bdaddr_t src; uint8_t *atval; if (status != 0) { DBG("Read characteristics by UUID failed: %s\n", att_ecode2str(status)); goto done; } list = dec_read_by_type_resp(pdu, plen); if (list == NULL) goto done; if (list->len != 4) { DBG("Appearance value: invalid data"); goto done; } /* A device shall have only one instance of the Appearance characteristic. */ atval = list->data[0] + 2; /* skip handle value */ app = att_get_u16(atval); adapter_get_address(adapter, &src); write_remote_appearance(&src, &device->bdaddr, device->bdaddr_type, app); done: att_data_list_free(list); if (device->attios == NULL && device->attios_offline == NULL) att_cleanup(device); } static void primary_cb(GSList *services, guint8 status, gpointer user_data) { struct browse_req *req = user_data; struct btd_device *device = req->device; struct gatt_primary *gap_prim = NULL; GSList *l, *uuids = NULL; if (status) { if (req->msg) { DBusMessage *reply; reply = btd_error_failed(req->msg, att_ecode2str(status)); g_dbus_send_message(req->conn, reply); } goto done; } device_set_temporary(device, FALSE); for (l = services; l; l = l->next) { struct gatt_primary *prim = l->data; if (strcmp(prim->uuid, GAP_SVC_UUID) == 0) gap_prim = prim; uuids = g_slist_append(uuids, prim->uuid); } device_register_services(req->conn, device, g_slist_copy(services), -1); device_probe_drivers(device, uuids); if (gap_prim) { /* Read appearance characteristic */ bt_uuid_t uuid; bt_uuid16_create(&uuid, APPEARANCE_CHR_UUID); gatt_read_char_by_uuid(device->attrib, gap_prim->range.start, gap_prim->range.end, &uuid, appearance_cb, device); } else if (device->attios == NULL && device->attios_offline == NULL) att_cleanup(device); g_slist_free(uuids); services_changed(device); if (req->msg) create_device_reply(device, req); store_services(device); done: device->browse = NULL; browse_request_free(req); } static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data) { struct att_callbacks *attcb = user_data; struct btd_device *device = attcb->user_data; GAttrib *attrib; g_io_channel_unref(device->att_io); device->att_io = NULL; if (gerr) { DBG("%s", gerr->message); if (attcb->error) attcb->error(gerr, user_data); goto done; } attrib = g_attrib_new(io); device->attachid = attrib_channel_attach(attrib); if (device->attachid == 0) error("Attribute server attach failure!"); device->attrib = attrib; device->cleanup_id = g_io_add_watch(io, G_IO_HUP, attrib_disconnected_cb, device); if (attcb->success) attcb->success(user_data); done: g_free(attcb); } static void att_error_cb(const GError *gerr, gpointer user_data) { struct att_callbacks *attcb = user_data; struct btd_device *device = attcb->user_data; if (device->auto_connect == FALSE) return; device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE, AUTO_CONNECTION_INTERVAL, att_connect, device, att_connect_dispatched); DBG("Enabling automatic connections"); } static void att_success_cb(gpointer user_data) { struct att_callbacks *attcb = user_data; struct btd_device *device = attcb->user_data; if (device->attios == NULL) return; g_slist_foreach(device->attios, attio_connected, device->attrib); } static gboolean att_connect(gpointer user_data) { struct btd_device *device = user_data; struct btd_adapter *adapter = device->adapter; struct att_callbacks *attcb; GIOChannel *io; GError *gerr = NULL; char addr[18]; bdaddr_t sba; adapter_get_address(adapter, &sba); ba2str(&device->bdaddr, addr); DBG("Connection attempt to: %s", addr); attcb = g_new0(struct att_callbacks, 1); attcb->error = att_error_cb; attcb->success = att_success_cb; attcb->user_data = device; if (device_is_bredr(device)) { io = bt_io_connect(BT_IO_L2CAP, att_connect_cb, attcb, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &sba, BT_IO_OPT_DEST_BDADDR, &device->bdaddr, BT_IO_OPT_PSM, ATT_PSM, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID); } else { io = bt_io_connect(BT_IO_L2CAP, att_connect_cb, attcb, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &sba, BT_IO_OPT_DEST_BDADDR, &device->bdaddr, BT_IO_OPT_DEST_TYPE, device->bdaddr_type, BT_IO_OPT_CID, ATT_CID, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID); } if (io == NULL) { error("ATT bt_io_connect(%s): %s", addr, gerr->message); g_error_free(gerr); g_free(attcb); return FALSE; } device->att_io = io; return FALSE; } static void att_browse_error_cb(const GError *gerr, gpointer user_data) { struct att_callbacks *attcb = user_data; struct btd_device *device = attcb->user_data; struct browse_req *req = device->browse; if (req->msg) { DBusMessage *reply; reply = btd_error_failed(req->msg, gerr->message); g_dbus_send_message(req->conn, reply); } device->browse = NULL; browse_request_free(req); } static void att_browse_cb(gpointer user_data) { struct att_callbacks *attcb = user_data; struct btd_device *device = attcb->user_data; gatt_discover_primary(device->attrib, NULL, primary_cb, device->browse); } int device_browse_primary(struct btd_device *device, DBusConnection *conn, DBusMessage *msg, gboolean secure) { struct btd_adapter *adapter = device->adapter; struct att_callbacks *attcb; struct browse_req *req; BtIOSecLevel sec_level; bdaddr_t src; if (device->browse) return -EBUSY; /* FIXME: GATT service updates (implemented in update_services() for * SDP) are not supported yet. It will be supported once client side * "Services Changed" characteristic handling is implemented. */ if (device->primaries) { error("Could not update GATT services"); return -ENOSYS; } req = g_new0(struct browse_req, 1); req->device = btd_device_ref(device); adapter_get_address(adapter, &src); device->browse = req; if (device->attrib) { gatt_discover_primary(device->attrib, NULL, primary_cb, req); goto done; } sec_level = secure ? BT_IO_SEC_HIGH : BT_IO_SEC_LOW; attcb = g_new0(struct att_callbacks, 1); attcb->error = att_browse_error_cb; attcb->success = att_browse_cb; attcb->user_data = device; device->att_io = bt_io_connect(BT_IO_L2CAP, att_connect_cb, attcb, NULL, NULL, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &device->bdaddr, BT_IO_OPT_DEST_TYPE, device->bdaddr_type, BT_IO_OPT_CID, ATT_CID, BT_IO_OPT_SEC_LEVEL, sec_level, BT_IO_OPT_INVALID); if (device->att_io == NULL) { device->browse = NULL; browse_request_free(req); g_free(attcb); return -EIO; } done: if (conn == NULL) conn = get_dbus_connection(); req->conn = dbus_connection_ref(conn); if (msg) { const char *sender = dbus_message_get_sender(msg); req->msg = dbus_message_ref(msg); /* Track the request owner to cancel it * automatically if the owner exits */ req->listener_id = g_dbus_add_disconnect_watch(conn, sender, discover_services_req_exit, req, NULL); } return 0; } int device_browse_sdp(struct btd_device *device, DBusConnection *conn, DBusMessage *msg, uuid_t *search, gboolean reverse) { struct btd_adapter *adapter = device->adapter; struct browse_req *req; bt_callback_t cb; bdaddr_t src; uuid_t uuid; int err; if (device->browse) return -EBUSY; adapter_get_address(adapter, &src); req = g_new0(struct browse_req, 1); req->device = btd_device_ref(device); if (search) { memcpy(&uuid, search, sizeof(uuid_t)); cb = search_cb; } else { sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]); init_browse(req, reverse); cb = browse_cb; } err = bt_search_service(&src, &device->bdaddr, &uuid, cb, req, NULL); if (err < 0) { browse_request_free(req); return err; } if (conn == NULL) conn = get_dbus_connection(); req->conn = dbus_connection_ref(conn); device->browse = req; if (msg) { const char *sender = dbus_message_get_sender(msg); req->msg = dbus_message_ref(msg); /* Track the request owner to cancel it * automatically if the owner exits */ req->listener_id = g_dbus_add_disconnect_watch(conn, sender, discover_services_req_exit, req, NULL); } return err; } struct btd_adapter *device_get_adapter(struct btd_device *device) { if (!device) return NULL; return device->adapter; } void device_get_address(struct btd_device *device, bdaddr_t *bdaddr, uint8_t *bdaddr_type) { bacpy(bdaddr, &device->bdaddr); if (bdaddr_type != NULL) *bdaddr_type = device->bdaddr_type; } void device_set_addr_type(struct btd_device *device, uint8_t bdaddr_type) { if (device == NULL) return; device->bdaddr_type = bdaddr_type; } uint8_t device_get_addr_type(struct btd_device *device) { return device->bdaddr_type; } const gchar *device_get_path(struct btd_device *device) { if (!device) return NULL; return device->path; } struct agent *device_get_agent(struct btd_device *device) { if (!device) return NULL; if (device->agent) return device->agent; return adapter_get_agent(device->adapter); } gboolean device_is_busy(struct btd_device *device) { return device->browse ? TRUE : FALSE; } gboolean device_is_temporary(struct btd_device *device) { return device->temporary; } void device_set_temporary(struct btd_device *device, gboolean temporary) { if (!device) return; DBG("temporary %d", temporary); device->temporary = temporary; } void device_set_bonded(struct btd_device *device, gboolean bonded) { if (!device) return; DBG("bonded %d", bonded); device->bonded = bonded; } void device_set_auto_connect(struct btd_device *device, gboolean enable) { char addr[18]; if (!device) return; ba2str(&device->bdaddr, addr); DBG("%s auto connect: %d", addr, enable); device->auto_connect = enable; /* Disabling auto connect */ if (enable == FALSE) { if (device->auto_id) g_source_remove(device->auto_id); return; } /* Enabling auto connect */ if (device->auto_id != 0) return; if (device->attrib) { DBG("Already connected"); return; } if (device->attios == NULL && device->attios_offline == NULL) return; device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, att_connect, device, att_connect_dispatched); } static gboolean start_discovery(gpointer user_data) { struct btd_device *device = user_data; if (device_is_bredr(device)) device_browse_sdp(device, NULL, NULL, NULL, TRUE); else device_browse_primary(device, NULL, NULL, FALSE); device->discov_timer = 0; return FALSE; } static DBusMessage *new_authentication_return(DBusMessage *msg, int status) { switch (status) { case 0x00: /* success */ return dbus_message_new_method_return(msg); case 0x04: /* page timeout */ return dbus_message_new_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", "Page Timeout"); case 0x08: /* connection timeout */ return dbus_message_new_error(msg, ERROR_INTERFACE ".ConnectionAttemptFailed", "Connection Timeout"); case 0x10: /* connection accept timeout */ case 0x22: /* LMP response timeout */ case 0x28: /* instant passed - is this a timeout? */ return dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationTimeout", "Authentication Timeout"); case 0x17: /* too frequent pairing attempts */ return dbus_message_new_error(msg, ERROR_INTERFACE ".RepeatedAttempts", "Repeated Attempts"); case 0x06: case 0x18: /* pairing not allowed (e.g. gw rejected attempt) */ return dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationRejected", "Authentication Rejected"); case 0x07: /* memory capacity */ case 0x09: /* connection limit */ case 0x0a: /* synchronous connection limit */ case 0x0d: /* limited resources */ case 0x13: /* user ended the connection */ case 0x14: /* terminated due to low resources */ case 0x16: /* connection terminated */ return dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationCanceled", "Authentication Canceled"); case 0x05: /* authentication failure */ case 0x0E: /* rejected due to security reasons - is this auth failure? */ case 0x25: /* encryption mode not acceptable - is this auth failure? */ case 0x26: /* link key cannot be changed - is this auth failure? */ case 0x29: /* pairing with unit key unsupported - is this auth failure? */ case 0x2f: /* insufficient security - is this auth failure? */ default: return dbus_message_new_error(msg, ERROR_INTERFACE ".AuthenticationFailed", "Authentication Failed"); } } static void bonding_request_free(struct bonding_req *bonding) { struct btd_device *device; if (!bonding) return; if (bonding->listener_id) g_dbus_remove_watch(bonding->conn, bonding->listener_id); if (bonding->msg) dbus_message_unref(bonding->msg); if (bonding->conn) dbus_connection_unref(bonding->conn); device = bonding->device; g_free(bonding); if (!device) return; device->bonding = NULL; if (!device->agent) return; agent_cancel(device->agent); agent_free(device->agent); device->agent = NULL; } void device_set_paired(struct btd_device *device, gboolean value) { DBusConnection *conn = get_dbus_connection(); if (device->paired == value) return; if (!value) btd_adapter_remove_bonding(device->adapter, &device->bdaddr, device->bdaddr_type); device->paired = value; emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Paired", DBUS_TYPE_BOOLEAN, &value); } static void device_agent_removed(struct agent *agent, void *user_data) { struct btd_device *device = user_data; device->agent = NULL; if (device->authr) device->authr->agent = NULL; } static struct bonding_req *bonding_request_new(DBusConnection *conn, DBusMessage *msg, struct btd_device *device, const char *agent_path, uint8_t capability) { struct bonding_req *bonding; const char *name = dbus_message_get_sender(msg); char addr[18]; ba2str(&device->bdaddr, addr); DBG("Requesting bonding for %s", addr); if (!agent_path) goto proceed; device->agent = agent_create(device->adapter, name, agent_path, capability, device_agent_removed, device); DBG("Temporary agent registered for %s at %s:%s", addr, name, agent_path); proceed: bonding = g_new0(struct bonding_req, 1); bonding->conn = dbus_connection_ref(conn); bonding->msg = dbus_message_ref(msg); return bonding; } static void create_bond_req_exit(DBusConnection *conn, void *user_data) { struct btd_device *device = user_data; char addr[18]; ba2str(&device->bdaddr, addr); DBG("%s: requestor exited before bonding was completed", addr); if (device->authr) device_cancel_authentication(device, FALSE); if (device->bonding) { device->bonding->listener_id = 0; device_request_disconnect(device, NULL); } } DBusMessage *device_create_bonding(struct btd_device *device, DBusConnection *conn, DBusMessage *msg, const char *agent_path, uint8_t capability) { struct btd_adapter *adapter = device->adapter; struct bonding_req *bonding; int err; if (device->bonding) return btd_error_in_progress(msg); if (device_is_bonded(device)) return btd_error_already_exists(msg); if (device_is_le(device)) { struct att_callbacks *attcb; GError *gerr = NULL; bdaddr_t sba; adapter_get_address(adapter, &sba); attcb = g_new0(struct att_callbacks, 1); attcb->user_data = device; device->att_io = bt_io_connect(BT_IO_L2CAP, att_connect_cb, attcb, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &sba, BT_IO_OPT_DEST_BDADDR, &device->bdaddr, BT_IO_OPT_DEST_TYPE, device->bdaddr_type, BT_IO_OPT_CID, ATT_CID, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (device->att_io == NULL) { DBusMessage *reply = btd_error_failed(msg, gerr->message); error("Bonding bt_io_connect(): %s", gerr->message); g_error_free(gerr); g_free(attcb); return reply; } } err = adapter_create_bonding(adapter, &device->bdaddr, device->bdaddr_type, capability); if (err < 0) return btd_error_failed(msg, strerror(-err)); bonding = bonding_request_new(conn, msg, device, agent_path, capability); bonding->listener_id = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), create_bond_req_exit, device, NULL); device->bonding = bonding; bonding->device = device; return NULL; } void device_simple_pairing_complete(struct btd_device *device, uint8_t status) { struct authentication_req *auth = device->authr; if (auth && (auth->type == AUTH_TYPE_NOTIFY_PASSKEY || auth->type == AUTH_TYPE_NOTIFY_PINCODE) && auth->agent) agent_cancel(auth->agent); } static void device_auth_req_free(struct btd_device *device) { if (device->authr) g_free(device->authr->pincode); g_free(device->authr); device->authr = NULL; } void device_bonding_complete(struct btd_device *device, uint8_t status) { struct bonding_req *bonding = device->bonding; struct authentication_req *auth = device->authr; DBG("bonding %p status 0x%02x", bonding, status); if (auth && (auth->type == AUTH_TYPE_NOTIFY_PASSKEY || auth->type == AUTH_TYPE_NOTIFY_PINCODE) && auth->agent) agent_cancel(auth->agent); if (status) { device_cancel_authentication(device, TRUE); device_cancel_bonding(device, status); return; } device_auth_req_free(device); /* If we're already paired nothing more is needed */ if (device->paired) return; device_set_paired(device, TRUE); /* If we were initiators start service discovery immediately. * However if the other end was the initator wait a few seconds * before SDP. This is due to potential IOP issues if the other * end starts doing SDP at the same time as us */ if (bonding) { DBG("Proceeding with service discovery"); /* If we are initiators remove any discovery timer and just * start discovering services directly */ if (device->discov_timer) { g_source_remove(device->discov_timer); device->discov_timer = 0; } if (device_is_bredr(device)) device_browse_sdp(device, bonding->conn, bonding->msg, NULL, FALSE); else device_browse_primary(device, bonding->conn, bonding->msg, FALSE); bonding_request_free(bonding); } else { if (!device->browse && !device->discov_timer && main_opts.reverse_sdp) { /* If we are not initiators and there is no currently * active discovery or discovery timer, set discovery * timer */ DBG("setting timer for reverse service discovery"); device->discov_timer = g_timeout_add_seconds( DISCOVERY_TIMER, start_discovery, device); } } } gboolean device_is_creating(struct btd_device *device, const char *sender) { DBusMessage *msg; if (device->bonding && device->bonding->msg) msg = device->bonding->msg; else if (device->browse && device->browse->msg) msg = device->browse->msg; else return FALSE; if (!dbus_message_is_method_call(msg, ADAPTER_INTERFACE, "CreatePairedDevice") && !dbus_message_is_method_call(msg, ADAPTER_INTERFACE, "CreateDevice")) return FALSE; if (sender == NULL) return TRUE; return g_str_equal(sender, dbus_message_get_sender(msg)); } gboolean device_is_bonding(struct btd_device *device, const char *sender) { struct bonding_req *bonding = device->bonding; if (!device->bonding) return FALSE; if (!sender) return TRUE; return g_str_equal(sender, dbus_message_get_sender(bonding->msg)); } void device_cancel_bonding(struct btd_device *device, uint8_t status) { struct bonding_req *bonding = device->bonding; DBusMessage *reply; char addr[18]; if (!bonding) return; ba2str(&device->bdaddr, addr); DBG("Canceling bonding request for %s", addr); if (device->authr) device_cancel_authentication(device, FALSE); reply = new_authentication_return(bonding->msg, status); g_dbus_send_message(bonding->conn, reply); bonding_request_cancel(bonding); bonding_request_free(bonding); } static void pincode_cb(struct agent *agent, DBusError *err, const char *pincode, void *data) { struct authentication_req *auth = data; struct btd_device *device = auth->device; struct btd_adapter *adapter = device_get_adapter(device); struct agent *adapter_agent = adapter_get_agent(adapter); if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) || g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) { if (auth->agent == adapter_agent || adapter_agent == NULL) goto done; if (agent_request_pincode(adapter_agent, device, pincode_cb, auth->secure, auth, NULL) < 0) goto done; auth->agent = adapter_agent; return; } done: /* No need to reply anything if the authentication already failed */ if (auth->cb == NULL) return; ((agent_pincode_cb) auth->cb)(agent, err, pincode, device); device->authr->cb = NULL; device->authr->agent = NULL; } static void confirm_cb(struct agent *agent, DBusError *err, void *data) { struct authentication_req *auth = data; struct btd_device *device = auth->device; struct btd_adapter *adapter = device_get_adapter(device); struct agent *adapter_agent = adapter_get_agent(adapter); if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) || g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) { if (auth->agent == adapter_agent || adapter_agent == NULL) goto done; if (agent_request_confirmation(adapter_agent, device, auth->passkey, confirm_cb, auth, NULL) < 0) goto done; auth->agent = adapter_agent; return; } done: /* No need to reply anything if the authentication already failed */ if (auth->cb == NULL) return; ((agent_cb) auth->cb)(agent, err, device); device->authr->cb = NULL; device->authr->agent = NULL; } static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey, void *data) { struct authentication_req *auth = data; struct btd_device *device = auth->device; struct btd_adapter *adapter = device_get_adapter(device); struct agent *adapter_agent = adapter_get_agent(adapter); if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) || g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) { if (auth->agent == adapter_agent || adapter_agent == NULL) goto done; if (agent_request_passkey(adapter_agent, device, passkey_cb, auth, NULL) < 0) goto done; auth->agent = adapter_agent; return; } done: /* No need to reply anything if the authentication already failed */ if (auth->cb == NULL) return; ((agent_passkey_cb) auth->cb)(agent, err, passkey, device); device->authr->cb = NULL; device->authr->agent = NULL; } static void display_pincode_cb(struct agent *agent, DBusError *err, void *data) { struct authentication_req *auth = data; struct btd_device *device = auth->device; struct btd_adapter *adapter = device_get_adapter(device); struct agent *adapter_agent = adapter_get_agent(adapter); if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) || g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) { /* Request a pincode if we fail to display one */ if (auth->agent == adapter_agent || adapter_agent == NULL) { if (agent_request_pincode(agent, device, pincode_cb, auth->secure, auth, NULL) < 0) goto done; return; } if (agent_display_pincode(adapter_agent, device, auth->pincode, display_pincode_cb, auth, NULL) < 0) goto done; auth->agent = adapter_agent; return; } done: /* No need to reply anything if the authentication already failed */ if (auth->cb == NULL) return; ((agent_pincode_cb) auth->cb)(agent, err, auth->pincode, device); g_free(device->authr->pincode); device->authr->pincode = NULL; device->authr->cb = NULL; device->authr->agent = NULL; } int device_request_authentication(struct btd_device *device, auth_type_t type, void *data, gboolean secure, void *cb) { struct authentication_req *auth; struct agent *agent; char addr[18]; int err; ba2str(&device->bdaddr, addr); DBG("Requesting agent authentication for %s", addr); if (device->authr) { error("Authentication already requested for %s", addr); return -EALREADY; } agent = device_get_agent(device); if (!agent) { error("No agent available for request type %d", type); return -EPERM; } auth = g_new0(struct authentication_req, 1); auth->agent = agent; auth->device = device; auth->cb = cb; auth->type = type; auth->secure = secure; device->authr = auth; switch (type) { case AUTH_TYPE_PINCODE: err = agent_request_pincode(agent, device, pincode_cb, secure, auth, NULL); break; case AUTH_TYPE_PASSKEY: err = agent_request_passkey(agent, device, passkey_cb, auth, NULL); break; case AUTH_TYPE_CONFIRM: auth->passkey = *((uint32_t *) data); err = agent_request_confirmation(agent, device, auth->passkey, confirm_cb, auth, NULL); break; case AUTH_TYPE_NOTIFY_PASSKEY: auth->passkey = *((uint32_t *) data); err = agent_display_passkey(agent, device, auth->passkey); break; case AUTH_TYPE_NOTIFY_PINCODE: auth->pincode = g_strdup((const char *) data); err = agent_display_pincode(agent, device, auth->pincode, display_pincode_cb, auth, NULL); break; default: err = -EINVAL; } if (err < 0) { error("Failed requesting authentication"); device_auth_req_free(device); } return err; } static void cancel_authentication(struct authentication_req *auth) { struct btd_device *device; struct agent *agent; DBusError err; if (!auth || !auth->cb) return; device = auth->device; agent = auth->agent; dbus_error_init(&err); dbus_set_error_const(&err, "org.bluez.Error.Canceled", NULL); switch (auth->type) { case AUTH_TYPE_PINCODE: ((agent_pincode_cb) auth->cb)(agent, &err, NULL, device); break; case AUTH_TYPE_CONFIRM: ((agent_cb) auth->cb)(agent, &err, device); break; case AUTH_TYPE_PASSKEY: ((agent_passkey_cb) auth->cb)(agent, &err, 0, device); break; case AUTH_TYPE_NOTIFY_PASSKEY: /* User Notify doesn't require any reply */ break; case AUTH_TYPE_NOTIFY_PINCODE: ((agent_pincode_cb) auth->cb)(agent, &err, NULL, device); break; } dbus_error_free(&err); auth->cb = NULL; } void device_cancel_authentication(struct btd_device *device, gboolean aborted) { struct authentication_req *auth = device->authr; char addr[18]; if (!auth) return; ba2str(&device->bdaddr, addr); DBG("Canceling authentication request for %s", addr); if (auth->agent) agent_cancel(auth->agent); if (!aborted) cancel_authentication(auth); device_auth_req_free(device); } gboolean device_is_authenticating(struct btd_device *device) { return (device->authr != NULL); } gboolean device_is_authorizing(struct btd_device *device) { return device->authorizing; } void device_set_authorizing(struct btd_device *device, gboolean auth) { device->authorizing = auth; } void device_register_services(DBusConnection *conn, struct btd_device *device, GSList *prim_list, int psm) { device->primaries = g_slist_concat(device->primaries, prim_list); device->services = attrib_client_register(conn, device, psm, NULL, prim_list); } GSList *btd_device_get_primaries(struct btd_device *device) { return device->primaries; } void btd_device_add_uuid(struct btd_device *device, const char *uuid) { GSList *uuid_list; char *new_uuid; if (g_slist_find_custom(device->uuids, uuid, (GCompareFunc) strcasecmp)) return; new_uuid = g_strdup(uuid); uuid_list = g_slist_append(NULL, new_uuid); device_probe_drivers(device, uuid_list); g_free(new_uuid); g_slist_free(uuid_list); store_profiles(device); services_changed(device); } const sdp_record_t *btd_device_get_record(struct btd_device *device, const char *uuid) { bdaddr_t src; if (device->tmp_records) { const sdp_record_t *record; record = find_record_in_list(device->tmp_records, uuid); if (record != NULL) return record; } adapter_get_address(device->adapter, &src); device->tmp_records = read_records(&src, &device->bdaddr); if (!device->tmp_records) return NULL; return find_record_in_list(device->tmp_records, uuid); } int btd_register_device_driver(struct btd_device_driver *driver) { device_drivers = g_slist_append(device_drivers, driver); return 0; } void btd_unregister_device_driver(struct btd_device_driver *driver) { device_drivers = g_slist_remove(device_drivers, driver); } struct btd_device *btd_device_ref(struct btd_device *device) { device->ref++; DBG("%p: ref=%d", device, device->ref); return device; } void btd_device_unref(struct btd_device *device) { DBusConnection *conn = get_dbus_connection(); gchar *path; device->ref--; DBG("%p: ref=%d", device, device->ref); if (device->ref > 0) return; path = g_strdup(device->path); g_dbus_unregister_interface(conn, path, DEVICE_INTERFACE); g_free(path); } void device_set_class(struct btd_device *device, uint32_t value) { DBusConnection *conn = get_dbus_connection(); emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Class", DBUS_TYPE_UINT32, &value); } static gboolean notify_attios(gpointer user_data) { struct btd_device *device = user_data; if (device->attrib == NULL) return FALSE; g_slist_foreach(device->attios_offline, attio_connected, device->attrib); device->attios = g_slist_concat(device->attios, device->attios_offline); device->attios_offline = NULL; return FALSE; } guint btd_device_add_attio_callback(struct btd_device *device, attio_connect_cb cfunc, attio_disconnect_cb dcfunc, gpointer user_data) { struct attio_data *attio; static guint attio_id = 0; DBG("%p registered ATT connection callback", device); attio = g_new0(struct attio_data, 1); attio->id = ++attio_id; attio->cfunc = cfunc; attio->dcfunc = dcfunc; attio->user_data = user_data; if (device->attrib && cfunc) { device->attios_offline = g_slist_append(device->attios_offline, attio); g_idle_add(notify_attios, device); return attio->id; } device->attios = g_slist_append(device->attios, attio); if (device->auto_id == 0) device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, att_connect, device, att_connect_dispatched); return attio->id; } static int attio_id_cmp(gconstpointer a, gconstpointer b) { const struct attio_data *attio = a; guint id = GPOINTER_TO_UINT(b); return attio->id - id; } gboolean btd_device_remove_attio_callback(struct btd_device *device, guint id) { struct attio_data *attio; GSList *l; l = g_slist_find_custom(device->attios, GUINT_TO_POINTER(id), attio_id_cmp); if (l) { attio = l->data; device->attios = g_slist_remove(device->attios, attio); } else { l = g_slist_find_custom(device->attios_offline, GUINT_TO_POINTER(id), attio_id_cmp); if (!l) return FALSE; attio = l->data; device->attios_offline = g_slist_remove(device->attios_offline, attio); } g_free(attio); if (device->attios != NULL || device->attios_offline != NULL) return TRUE; if (device->auto_id) { g_source_remove(device->auto_id); device->auto_id = 0; } att_cleanup(device); return TRUE; } void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src, uint16_t vendor_id, uint16_t product_id, uint16_t product_ver) { device_set_vendor(device, vendor_id); device_set_vendor_src(device, vendor_id_src); device_set_product(device, product_id); device_set_version(device, product_ver); } bluez-4.101/src/eir.h0000644000000000000000000000470111766125764011267 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define EIR_FLAGS 0x01 /* flags */ #define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ #define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ #define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ #define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ #define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ #define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ #define EIR_NAME_SHORT 0x08 /* shortened local name */ #define EIR_NAME_COMPLETE 0x09 /* complete local name */ #define EIR_TX_POWER 0x0A /* transmit power level */ #define EIR_CLASS_OF_DEV 0x0D /* Class of Device */ #define EIR_DEVICE_ID 0x10 /* device ID */ #define EIR_GAP_APPEARANCE 0x19 /* GAP appearance */ struct uuid_info { uuid_t uuid; uint8_t svc_hint; }; struct eir_data { GSList *services; int flags; char *name; uint8_t dev_class[3]; uint16_t appearance; gboolean name_complete; }; void eir_data_free(struct eir_data *eir); int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len); void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor, uint16_t did_product, uint16_t did_version, uint16_t did_source, GSList *uuids, uint8_t *data); gboolean eir_has_data_type(uint8_t *data, size_t len, uint8_t type); size_t eir_append_data(uint8_t *eir, size_t eir_len, uint8_t type, uint8_t *data, size_t data_len); size_t eir_length(uint8_t *eir, size_t maxlen); bluez-4.101/src/uinput.h0000644000000000000000000004373311766125764012044 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __UINPUT_H #define __UINPUT_H #ifdef __cplusplus extern "C" { #endif #include #include #include /* Events */ #define EV_SYN 0x00 #define EV_KEY 0x01 #define EV_REL 0x02 #define EV_ABS 0x03 #define EV_MSC 0x04 #define EV_LED 0x11 #define EV_SND 0x12 #define EV_REP 0x14 #define EV_FF 0x15 #define EV_PWR 0x16 #define EV_FF_STATUS 0x17 #define EV_MAX 0x1f /* Synchronization events */ #define SYN_REPORT 0 #define SYN_CONFIG 1 /* * Keys and buttons * * Most of the keys/buttons are modelled after USB HUT 1.12 * (see http://www.usb.org/developers/hidpage). * Abbreviations in the comments: * AC - Application Control * AL - Application Launch Button * SC - System Control */ #define KEY_RESERVED 0 #define KEY_ESC 1 #define KEY_1 2 #define KEY_2 3 #define KEY_3 4 #define KEY_4 5 #define KEY_5 6 #define KEY_6 7 #define KEY_7 8 #define KEY_8 9 #define KEY_9 10 #define KEY_0 11 #define KEY_MINUS 12 #define KEY_EQUAL 13 #define KEY_BACKSPACE 14 #define KEY_TAB 15 #define KEY_Q 16 #define KEY_W 17 #define KEY_E 18 #define KEY_R 19 #define KEY_T 20 #define KEY_Y 21 #define KEY_U 22 #define KEY_I 23 #define KEY_O 24 #define KEY_P 25 #define KEY_LEFTBRACE 26 #define KEY_RIGHTBRACE 27 #define KEY_ENTER 28 #define KEY_LEFTCTRL 29 #define KEY_A 30 #define KEY_S 31 #define KEY_D 32 #define KEY_F 33 #define KEY_G 34 #define KEY_H 35 #define KEY_J 36 #define KEY_K 37 #define KEY_L 38 #define KEY_SEMICOLON 39 #define KEY_APOSTROPHE 40 #define KEY_GRAVE 41 #define KEY_LEFTSHIFT 42 #define KEY_BACKSLASH 43 #define KEY_Z 44 #define KEY_X 45 #define KEY_C 46 #define KEY_V 47 #define KEY_B 48 #define KEY_N 49 #define KEY_M 50 #define KEY_COMMA 51 #define KEY_DOT 52 #define KEY_SLASH 53 #define KEY_RIGHTSHIFT 54 #define KEY_KPASTERISK 55 #define KEY_LEFTALT 56 #define KEY_SPACE 57 #define KEY_CAPSLOCK 58 #define KEY_F1 59 #define KEY_F2 60 #define KEY_F3 61 #define KEY_F4 62 #define KEY_F5 63 #define KEY_F6 64 #define KEY_F7 65 #define KEY_F8 66 #define KEY_F9 67 #define KEY_F10 68 #define KEY_NUMLOCK 69 #define KEY_SCROLLLOCK 70 #define KEY_KP7 71 #define KEY_KP8 72 #define KEY_KP9 73 #define KEY_KPMINUS 74 #define KEY_KP4 75 #define KEY_KP5 76 #define KEY_KP6 77 #define KEY_KPPLUS 78 #define KEY_KP1 79 #define KEY_KP2 80 #define KEY_KP3 81 #define KEY_KP0 82 #define KEY_KPDOT 83 #define KEY_ZENKAKUHANKAKU 85 #define KEY_102ND 86 #define KEY_F11 87 #define KEY_F12 88 #define KEY_RO 89 #define KEY_KATAKANA 90 #define KEY_HIRAGANA 91 #define KEY_HENKAN 92 #define KEY_KATAKANAHIRAGANA 93 #define KEY_MUHENKAN 94 #define KEY_KPJPCOMMA 95 #define KEY_KPENTER 96 #define KEY_RIGHTCTRL 97 #define KEY_KPSLASH 98 #define KEY_SYSRQ 99 #define KEY_RIGHTALT 100 #define KEY_LINEFEED 101 #define KEY_HOME 102 #define KEY_UP 103 #define KEY_PAGEUP 104 #define KEY_LEFT 105 #define KEY_RIGHT 106 #define KEY_END 107 #define KEY_DOWN 108 #define KEY_PAGEDOWN 109 #define KEY_INSERT 110 #define KEY_DELETE 111 #define KEY_MACRO 112 #define KEY_MUTE 113 #define KEY_VOLUMEDOWN 114 #define KEY_VOLUMEUP 115 #define KEY_POWER 116 /* SC System Power Down */ #define KEY_KPEQUAL 117 #define KEY_KPPLUSMINUS 118 #define KEY_PAUSE 119 #define KEY_KPCOMMA 121 #define KEY_HANGEUL 122 #define KEY_HANGUEL KEY_HANGEUL #define KEY_HANJA 123 #define KEY_YEN 124 #define KEY_LEFTMETA 125 #define KEY_RIGHTMETA 126 #define KEY_COMPOSE 127 #define KEY_STOP 128 /* AC Stop */ #define KEY_AGAIN 129 #define KEY_PROPS 130 /* AC Properties */ #define KEY_UNDO 131 /* AC Undo */ #define KEY_FRONT 132 #define KEY_COPY 133 /* AC Copy */ #define KEY_OPEN 134 /* AC Open */ #define KEY_PASTE 135 /* AC Paste */ #define KEY_FIND 136 /* AC Search */ #define KEY_CUT 137 /* AC Cut */ #define KEY_HELP 138 /* AL Integrated Help Center */ #define KEY_MENU 139 /* Menu (show menu) */ #define KEY_CALC 140 /* AL Calculator */ #define KEY_SETUP 141 #define KEY_SLEEP 142 /* SC System Sleep */ #define KEY_WAKEUP 143 /* System Wake Up */ #define KEY_FILE 144 /* AL Local Machine Browser */ #define KEY_SENDFILE 145 #define KEY_DELETEFILE 146 #define KEY_XFER 147 #define KEY_PROG1 148 #define KEY_PROG2 149 #define KEY_WWW 150 /* AL Internet Browser */ #define KEY_MSDOS 151 #define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */ #define KEY_SCREENLOCK KEY_COFFEE #define KEY_DIRECTION 153 #define KEY_CYCLEWINDOWS 154 #define KEY_MAIL 155 #define KEY_BOOKMARKS 156 /* AC Bookmarks */ #define KEY_COMPUTER 157 #define KEY_BACK 158 /* AC Back */ #define KEY_FORWARD 159 /* AC Forward */ #define KEY_CLOSECD 160 #define KEY_EJECTCD 161 #define KEY_EJECTCLOSECD 162 #define KEY_NEXTSONG 163 #define KEY_PLAYPAUSE 164 #define KEY_PREVIOUSSONG 165 #define KEY_STOPCD 166 #define KEY_RECORD 167 #define KEY_REWIND 168 #define KEY_PHONE 169 /* Media Select Telephone */ #define KEY_ISO 170 #define KEY_CONFIG 171 /* AL Consumer Control Configuration */ #define KEY_HOMEPAGE 172 /* AC Home */ #define KEY_REFRESH 173 /* AC Refresh */ #define KEY_EXIT 174 /* AC Exit */ #define KEY_MOVE 175 #define KEY_EDIT 176 #define KEY_SCROLLUP 177 #define KEY_SCROLLDOWN 178 #define KEY_KPLEFTPAREN 179 #define KEY_KPRIGHTPAREN 180 #define KEY_NEW 181 /* AC New */ #define KEY_REDO 182 /* AC Redo/Repeat */ #define KEY_F13 183 #define KEY_F14 184 #define KEY_F15 185 #define KEY_F16 186 #define KEY_F17 187 #define KEY_F18 188 #define KEY_F19 189 #define KEY_F20 190 #define KEY_F21 191 #define KEY_F22 192 #define KEY_F23 193 #define KEY_F24 194 #define KEY_PLAYCD 200 #define KEY_PAUSECD 201 #define KEY_PROG3 202 #define KEY_PROG4 203 #define KEY_SUSPEND 205 #define KEY_CLOSE 206 /* AC Close */ #define KEY_PLAY 207 #define KEY_FASTFORWARD 208 #define KEY_BASSBOOST 209 #define KEY_PRINT 210 /* AC Print */ #define KEY_HP 211 #define KEY_CAMERA 212 #define KEY_SOUND 213 #define KEY_QUESTION 214 #define KEY_EMAIL 215 #define KEY_CHAT 216 #define KEY_SEARCH 217 #define KEY_CONNECT 218 #define KEY_FINANCE 219 /* AL Checkbook/Finance */ #define KEY_SPORT 220 #define KEY_SHOP 221 #define KEY_ALTERASE 222 #define KEY_CANCEL 223 /* AC Cancel */ #define KEY_BRIGHTNESSDOWN 224 #define KEY_BRIGHTNESSUP 225 #define KEY_MEDIA 226 #define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video outputs (Monitor/LCD/TV-out/etc) */ #define KEY_KBDILLUMTOGGLE 228 #define KEY_KBDILLUMDOWN 229 #define KEY_KBDILLUMUP 230 #define KEY_SEND 231 /* AC Send */ #define KEY_REPLY 232 /* AC Reply */ #define KEY_FORWARDMAIL 233 /* AC Forward Msg */ #define KEY_SAVE 234 /* AC Save */ #define KEY_DOCUMENTS 235 #define KEY_BATTERY 236 #define KEY_BLUETOOTH 237 #define KEY_WLAN 238 #define KEY_UWB 239 #define KEY_UNKNOWN 240 #define KEY_VIDEO_NEXT 241 /* drive next video source */ #define KEY_VIDEO_PREV 242 /* drive previous video source */ #define KEY_BRIGHTNESS_CYCLE 243 /* brightness up, after max is min */ #define KEY_BRIGHTNESS_ZERO 244 /* brightness off, use ambient */ #define KEY_DISPLAY_OFF 245 /* display device to off state */ #define KEY_WIMAX 246 /* Range 248 - 255 is reserved for special needs of AT keyboard driver */ #define BTN_MISC 0x100 #define BTN_0 0x100 #define BTN_1 0x101 #define BTN_2 0x102 #define BTN_3 0x103 #define BTN_4 0x104 #define BTN_5 0x105 #define BTN_6 0x106 #define BTN_7 0x107 #define BTN_8 0x108 #define BTN_9 0x109 #define BTN_MOUSE 0x110 #define BTN_LEFT 0x110 #define BTN_RIGHT 0x111 #define BTN_MIDDLE 0x112 #define BTN_SIDE 0x113 #define BTN_EXTRA 0x114 #define BTN_FORWARD 0x115 #define BTN_BACK 0x116 #define BTN_TASK 0x117 #define BTN_JOYSTICK 0x120 #define BTN_TRIGGER 0x120 #define BTN_THUMB 0x121 #define BTN_THUMB2 0x122 #define BTN_TOP 0x123 #define BTN_TOP2 0x124 #define BTN_PINKIE 0x125 #define BTN_BASE 0x126 #define BTN_BASE2 0x127 #define BTN_BASE3 0x128 #define BTN_BASE4 0x129 #define BTN_BASE5 0x12a #define BTN_BASE6 0x12b #define BTN_DEAD 0x12f #define BTN_GAMEPAD 0x130 #define BTN_A 0x130 #define BTN_B 0x131 #define BTN_C 0x132 #define BTN_X 0x133 #define BTN_Y 0x134 #define BTN_Z 0x135 #define BTN_TL 0x136 #define BTN_TR 0x137 #define BTN_TL2 0x138 #define BTN_TR2 0x139 #define BTN_SELECT 0x13a #define BTN_START 0x13b #define BTN_MODE 0x13c #define BTN_THUMBL 0x13d #define BTN_THUMBR 0x13e #define BTN_DIGI 0x140 #define BTN_TOOL_PEN 0x140 #define BTN_TOOL_RUBBER 0x141 #define BTN_TOOL_BRUSH 0x142 #define BTN_TOOL_PENCIL 0x143 #define BTN_TOOL_AIRBRUSH 0x144 #define BTN_TOOL_FINGER 0x145 #define BTN_TOOL_MOUSE 0x146 #define BTN_TOOL_LENS 0x147 #define BTN_TOUCH 0x14a #define BTN_STYLUS 0x14b #define BTN_STYLUS2 0x14c #define BTN_TOOL_DOUBLETAP 0x14d #define BTN_TOOL_TRIPLETAP 0x14e #define BTN_WHEEL 0x150 #define BTN_GEAR_DOWN 0x150 #define BTN_GEAR_UP 0x151 #define KEY_OK 0x160 #define KEY_SELECT 0x161 #define KEY_GOTO 0x162 #define KEY_CLEAR 0x163 #define KEY_POWER2 0x164 #define KEY_OPTION 0x165 #define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */ #define KEY_TIME 0x167 #define KEY_VENDOR 0x168 #define KEY_ARCHIVE 0x169 #define KEY_PROGRAM 0x16a /* Media Select Program Guide */ #define KEY_CHANNEL 0x16b #define KEY_FAVORITES 0x16c #define KEY_EPG 0x16d #define KEY_PVR 0x16e /* Media Select Home */ #define KEY_MHP 0x16f #define KEY_LANGUAGE 0x170 #define KEY_TITLE 0x171 #define KEY_SUBTITLE 0x172 #define KEY_ANGLE 0x173 #define KEY_ZOOM 0x174 #define KEY_MODE 0x175 #define KEY_KEYBOARD 0x176 #define KEY_SCREEN 0x177 #define KEY_PC 0x178 /* Media Select Computer */ #define KEY_TV 0x179 /* Media Select TV */ #define KEY_TV2 0x17a /* Media Select Cable */ #define KEY_VCR 0x17b /* Media Select VCR */ #define KEY_VCR2 0x17c /* VCR Plus */ #define KEY_SAT 0x17d /* Media Select Satellite */ #define KEY_SAT2 0x17e #define KEY_CD 0x17f /* Media Select CD */ #define KEY_TAPE 0x180 /* Media Select Tape */ #define KEY_RADIO 0x181 #define KEY_TUNER 0x182 /* Media Select Tuner */ #define KEY_PLAYER 0x183 #define KEY_TEXT 0x184 #define KEY_DVD 0x185 /* Media Select DVD */ #define KEY_AUX 0x186 #define KEY_MP3 0x187 #define KEY_AUDIO 0x188 #define KEY_VIDEO 0x189 #define KEY_DIRECTORY 0x18a #define KEY_LIST 0x18b #define KEY_MEMO 0x18c /* Media Select Messages */ #define KEY_CALENDAR 0x18d #define KEY_RED 0x18e #define KEY_GREEN 0x18f #define KEY_YELLOW 0x190 #define KEY_BLUE 0x191 #define KEY_CHANNELUP 0x192 /* Channel Increment */ #define KEY_CHANNELDOWN 0x193 /* Channel Decrement */ #define KEY_FIRST 0x194 #define KEY_LAST 0x195 /* Recall Last */ #define KEY_AB 0x196 #define KEY_NEXT 0x197 #define KEY_RESTART 0x198 #define KEY_SLOW 0x199 #define KEY_SHUFFLE 0x19a #define KEY_BREAK 0x19b #define KEY_PREVIOUS 0x19c #define KEY_DIGITS 0x19d #define KEY_TEEN 0x19e #define KEY_TWEN 0x19f #define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */ #define KEY_GAMES 0x1a1 /* Media Select Games */ #define KEY_ZOOMIN 0x1a2 /* AC Zoom In */ #define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */ #define KEY_ZOOMRESET 0x1a4 /* AC Zoom */ #define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */ #define KEY_EDITOR 0x1a6 /* AL Text Editor */ #define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */ #define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */ #define KEY_PRESENTATION 0x1a9 /* AL Presentation App */ #define KEY_DATABASE 0x1aa /* AL Database App */ #define KEY_NEWS 0x1ab /* AL Newsreader */ #define KEY_VOICEMAIL 0x1ac /* AL Voicemail */ #define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */ #define KEY_MESSENGER 0x1ae /* AL Instant Messaging */ #define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */ #define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */ #define KEY_LOGOFF 0x1b1 /* AL Logoff */ #define KEY_DOLLAR 0x1b2 #define KEY_EURO 0x1b3 #define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */ #define KEY_FRAMEFORWARD 0x1b5 #define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */ #define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */ #define KEY_DEL_EOL 0x1c0 #define KEY_DEL_EOS 0x1c1 #define KEY_INS_LINE 0x1c2 #define KEY_DEL_LINE 0x1c3 #define KEY_FN 0x1d0 #define KEY_FN_ESC 0x1d1 #define KEY_FN_F1 0x1d2 #define KEY_FN_F2 0x1d3 #define KEY_FN_F3 0x1d4 #define KEY_FN_F4 0x1d5 #define KEY_FN_F5 0x1d6 #define KEY_FN_F6 0x1d7 #define KEY_FN_F7 0x1d8 #define KEY_FN_F8 0x1d9 #define KEY_FN_F9 0x1da #define KEY_FN_F10 0x1db #define KEY_FN_F11 0x1dc #define KEY_FN_F12 0x1dd #define KEY_FN_1 0x1de #define KEY_FN_2 0x1df #define KEY_FN_D 0x1e0 #define KEY_FN_E 0x1e1 #define KEY_FN_F 0x1e2 #define KEY_FN_S 0x1e3 #define KEY_FN_B 0x1e4 #define KEY_BRL_DOT1 0x1f1 #define KEY_BRL_DOT2 0x1f2 #define KEY_BRL_DOT3 0x1f3 #define KEY_BRL_DOT4 0x1f4 #define KEY_BRL_DOT5 0x1f5 #define KEY_BRL_DOT6 0x1f6 #define KEY_BRL_DOT7 0x1f7 #define KEY_BRL_DOT8 0x1f8 #define KEY_BRL_DOT9 0x1f9 #define KEY_BRL_DOT10 0x1fa /* We avoid low common keys in module aliases so they don't get huge. */ #define KEY_MIN_INTERESTING KEY_MUTE #define KEY_MAX 0x1ff #define KEY_CNT (KEY_MAX+1) /* * Relative axes */ #define REL_X 0x00 #define REL_Y 0x01 #define REL_Z 0x02 #define REL_RX 0x03 #define REL_RY 0x04 #define REL_RZ 0x05 #define REL_HWHEEL 0x06 #define REL_DIAL 0x07 #define REL_WHEEL 0x08 #define REL_MISC 0x09 #define REL_MAX 0x0f #define REL_CNT (REL_MAX+1) /* * Absolute axes */ #define ABS_X 0x00 #define ABS_Y 0x01 #define ABS_Z 0x02 #define ABS_RX 0x03 #define ABS_RY 0x04 #define ABS_RZ 0x05 #define ABS_THROTTLE 0x06 #define ABS_RUDDER 0x07 #define ABS_WHEEL 0x08 #define ABS_GAS 0x09 #define ABS_BRAKE 0x0a #define ABS_HAT0X 0x10 #define ABS_HAT0Y 0x11 #define ABS_HAT1X 0x12 #define ABS_HAT1Y 0x13 #define ABS_HAT2X 0x14 #define ABS_HAT2Y 0x15 #define ABS_HAT3X 0x16 #define ABS_HAT3Y 0x17 #define ABS_PRESSURE 0x18 #define ABS_DISTANCE 0x19 #define ABS_TILT_X 0x1a #define ABS_TILT_Y 0x1b #define ABS_TOOL_WIDTH 0x1c #define ABS_VOLUME 0x20 #define ABS_MISC 0x28 #define ABS_MAX 0x3f #define ABS_CNT (ABS_MAX+1) /* * Switch events */ #define SW_LID 0x00 /* set = lid shut */ #define SW_TABLET_MODE 0x01 /* set = tablet mode */ #define SW_HEADPHONE_INSERT 0x02 /* set = inserted */ #define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" set = radio enabled */ #define SW_RADIO SW_RFKILL_ALL /* deprecated */ #define SW_MICROPHONE_INSERT 0x04 /* set = inserted */ #define SW_DOCK 0x05 /* set = plugged into dock */ #define SW_MAX 0x0f #define SW_CNT (SW_MAX+1) /* * Misc events */ #define MSC_SERIAL 0x00 #define MSC_PULSELED 0x01 #define MSC_GESTURE 0x02 #define MSC_RAW 0x03 #define MSC_SCAN 0x04 #define MSC_MAX 0x07 #define MSC_CNT (MSC_MAX+1) /* * LEDs */ #define LED_NUML 0x00 #define LED_CAPSL 0x01 #define LED_SCROLLL 0x02 #define LED_COMPOSE 0x03 #define LED_KANA 0x04 #define LED_SLEEP 0x05 #define LED_SUSPEND 0x06 #define LED_MUTE 0x07 #define LED_MISC 0x08 #define LED_MAIL 0x09 #define LED_CHARGING 0x0a #define LED_MAX 0x0f #define LED_CNT (LED_MAX+1) /* * Autorepeat values */ #define REP_DELAY 0x00 #define REP_PERIOD 0x01 #define REP_MAX 0x01 /* * Sounds */ #define SND_CLICK 0x00 #define SND_BELL 0x01 #define SND_TONE 0x02 #define SND_MAX 0x07 #define SND_CNT (SND_MAX+1) /* * IDs. */ #define ID_BUS 0 #define ID_VENDOR 1 #define ID_PRODUCT 2 #define ID_VERSION 3 #define BUS_PCI 0x01 #define BUS_ISAPNP 0x02 #define BUS_USB 0x03 #define BUS_HIL 0x04 #define BUS_BLUETOOTH 0x05 #define BUS_VIRTUAL 0x06 #define BUS_ISA 0x10 #define BUS_I8042 0x11 #define BUS_XTKBD 0x12 #define BUS_RS232 0x13 #define BUS_GAMEPORT 0x14 #define BUS_PARPORT 0x15 #define BUS_AMIGA 0x16 #define BUS_ADB 0x17 #define BUS_I2C 0x18 #define BUS_HOST 0x19 #define BUS_GSC 0x1A #define BUS_ATARI 0x1B /* User input interface */ #define UINPUT_IOCTL_BASE 'U' #define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1) #define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2) #define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int) #define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int) #define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int) #define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int) #define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int) #define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int) #define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int) #define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, int) #define UI_SET_PHYS _IOW(UINPUT_IOCTL_BASE, 108, char*) #define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int) #ifndef NBITS #define NBITS(x) ((((x) - 1) / (sizeof(long) * 8)) + 1) #endif #define UINPUT_MAX_NAME_SIZE 80 struct uinput_id { uint16_t bustype; uint16_t vendor; uint16_t product; uint16_t version; }; struct uinput_dev { char name[UINPUT_MAX_NAME_SIZE]; struct uinput_id id; int ff_effects_max; int absmax[ABS_MAX + 1]; int absmin[ABS_MAX + 1]; int absfuzz[ABS_MAX + 1]; int absflat[ABS_MAX + 1]; }; struct uinput_event { struct timeval time; uint16_t type; uint16_t code; int32_t value; }; #ifdef __cplusplus } #endif #endif /* __UINPUT_H */ bluez-4.101/src/ppoll.h0000644000000000000000000000055011272762165011626 00000000000000#ifdef ppoll #undef ppoll #endif #define ppoll compat_ppoll static inline int compat_ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout, const sigset_t *sigmask) { if (timeout == NULL) return poll(fds, nfds, -1); else if (timeout->tv_sec == 0) return poll(fds, nfds, 500); else return poll(fds, nfds, timeout->tv_sec * 1000); } bluez-4.101/src/org.bluez.service0000644000000000000000000000013711766125764013627 00000000000000[D-BUS Service] Name=org.bluez Exec=/bin/false User=root SystemdService=dbus-org.bluez.service bluez-4.101/src/storage.h0000644000000000000000000001315211766125764012154 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2002-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "textfile.h" int read_device_alias(const char *src, const char *dst, char *alias, size_t size); int write_device_alias(const char *src, const char *dst, const char *alias); int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout); int read_discoverable_timeout(const char *src, int *timeout); int write_pairable_timeout(bdaddr_t *bdaddr, int timeout); int read_pairable_timeout(const char *src, int *timeout); int write_device_mode(bdaddr_t *bdaddr, const char *mode); int read_device_mode(const char *src, char *mode, int length); int read_on_mode(const char *src, char *mode, int length); int write_local_name(bdaddr_t *bdaddr, const char *name); int read_local_name(bdaddr_t *bdaddr, char *name); int write_local_class(bdaddr_t *bdaddr, uint8_t *class); int read_local_class(bdaddr_t *bdaddr, uint8_t *class); int write_remote_appearance(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint16_t appearance); int read_remote_appearance(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint16_t *appearance); int write_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class); int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class); int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name); int read_device_name(const char *src, const char *dst, char *name); int write_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data, uint8_t data_len); int read_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data); int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer, uint8_t lmp_ver, uint16_t lmp_subver); int write_features_info(bdaddr_t *local, bdaddr_t *peer, unsigned char *page1, unsigned char *page2); int read_remote_features(bdaddr_t *local, bdaddr_t *peer, unsigned char *page1, unsigned char *page2); int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm); int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm); int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length); int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type); ssize_t read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin); gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service); int write_trust(const char *src, const char *addr, const char *service, gboolean trust); int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles); int delete_entry(bdaddr_t *src, const char *storage, const char *key); int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec); sdp_record_t *record_from_string(const gchar *str); sdp_record_t *fetch_record(const gchar *src, const gchar *dst, const uint32_t handle); int delete_record(const gchar *src, const gchar *dst, const uint32_t handle); void delete_all_records(const bdaddr_t *src, const bdaddr_t *dst); sdp_list_t *read_records(const bdaddr_t *src, const bdaddr_t *dst); sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid); int store_device_id(const gchar *src, const gchar *dst, const uint16_t source, const uint16_t vendor, const uint16_t product, const uint16_t version); int read_device_id(const gchar *src, const gchar *dst, uint16_t *source, uint16_t *vendor, uint16_t *product, uint16_t *version); int write_device_pairable(bdaddr_t *local, gboolean mode); int read_device_pairable(bdaddr_t *local, gboolean *mode); gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote); int write_blocked(const bdaddr_t *local, const bdaddr_t *remote, gboolean blocked); int write_device_services(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, const char *services); int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type); char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type); int write_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, uint16_t handle, const char *chars); char *read_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, uint16_t handle); int write_device_attribute(const bdaddr_t *sba, const bdaddr_t *dba, uint8_t bdaddr_type, uint16_t handle, const char *chars); int read_device_attributes(const bdaddr_t *sba, textfile_cb func, void *data); int read_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint16_t handle, uint16_t *value); int write_device_ccc(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint16_t handle, uint16_t value); void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer); int write_longtermkeys(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, const char *key); gboolean has_longtermkeys(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type); bluez-4.101/src/textfile.c0000644000000000000000000002042511766125764012330 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include "textfile.h" int create_dirs(const char *filename, const mode_t mode) { struct stat st; char dir[PATH_MAX + 1], *prev, *next; int err; err = stat(filename, &st); if (!err && S_ISREG(st.st_mode)) return 0; memset(dir, 0, PATH_MAX + 1); strcat(dir, "/"); prev = strchr(filename, '/'); while (prev) { next = strchr(prev + 1, '/'); if (!next) break; if (next - prev == 1) { prev = next; continue; } strncat(dir, prev + 1, next - prev); mkdir(dir, mode); prev = next; } return 0; } int create_file(const char *filename, const mode_t mode) { int fd; umask(S_IWGRP | S_IWOTH); create_dirs(filename, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); fd = open(filename, O_RDWR | O_CREAT, mode); if (fd < 0) return fd; close(fd); return 0; } int create_name(char *buf, size_t size, const char *path, const char *address, const char *name) { return snprintf(buf, size, "%s/%s/%s", path, address, name); } static inline char *find_key(char *map, size_t size, const char *key, size_t len, int icase) { char *ptr = map; size_t ptrlen = size; while (ptrlen > len + 1) { int cmp = (icase) ? strncasecmp(ptr, key, len) : strncmp(ptr, key, len); if (cmp == 0) { if (ptr == map) return ptr; if ((*(ptr - 1) == '\r' || *(ptr - 1) == '\n') && *(ptr + len) == ' ') return ptr; } if (icase) { char *p1 = memchr(ptr + 1, tolower(*key), ptrlen - 1); char *p2 = memchr(ptr + 1, toupper(*key), ptrlen - 1); if (!p1) ptr = p2; else if (!p2) ptr = p1; else ptr = (p1 < p2) ? p1 : p2; } else ptr = memchr(ptr + 1, *key, ptrlen - 1); if (!ptr) return NULL; ptrlen = size - (ptr - map); } return NULL; } static inline int write_key_value(int fd, const char *key, const char *value) { char *str; size_t size; int err = 0; size = strlen(key) + strlen(value) + 2; str = malloc(size + 1); if (!str) return ENOMEM; sprintf(str, "%s %s\n", key, value); if (write(fd, str, size) < 0) err = -errno; free(str); return err; } static char *strnpbrk(const char *s, ssize_t len, const char *accept) { const char *p = s; const char *end; end = s + len - 1; while (p <= end && *p) { const char *a = accept; while (*a) { if (*p == *a) return (char *) p; a++; } p++; } return NULL; } static int write_key(const char *pathname, const char *key, const char *value, int icase) { struct stat st; char *map, *off, *end, *str; off_t size; size_t base; int fd, len, err = 0; fd = open(pathname, O_RDWR); if (fd < 0) return -errno; if (flock(fd, LOCK_EX) < 0) { err = -errno; goto close; } if (fstat(fd, &st) < 0) { err = -errno; goto unlock; } size = st.st_size; if (!size) { if (value) { lseek(fd, size, SEEK_SET); err = write_key_value(fd, key, value); } goto unlock; } map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_LOCKED, fd, 0); if (!map || map == MAP_FAILED) { err = -errno; goto unlock; } len = strlen(key); off = find_key(map, size, key, len, icase); if (!off) { munmap(map, size); if (value) { lseek(fd, size, SEEK_SET); err = write_key_value(fd, key, value); } goto unlock; } base = off - map; end = strnpbrk(off, size, "\r\n"); if (!end) { err = -EILSEQ; goto unmap; } if (value && ((ssize_t) strlen(value) == end - off - len - 1) && !strncmp(off + len + 1, value, end - off - len - 1)) goto unmap; len = strspn(end, "\r\n"); end += len; len = size - (end - map); if (!len) { munmap(map, size); if (ftruncate(fd, base) < 0) { err = -errno; goto unlock; } lseek(fd, base, SEEK_SET); if (value) err = write_key_value(fd, key, value); goto unlock; } if (len < 0 || len > size) { err = -EILSEQ; goto unmap; } str = malloc(len); if (!str) { err = -errno; goto unmap; } memcpy(str, end, len); munmap(map, size); if (ftruncate(fd, base) < 0) { err = -errno; free(str); goto unlock; } lseek(fd, base, SEEK_SET); if (value) err = write_key_value(fd, key, value); if (write(fd, str, len) < 0) err = -errno; free(str); goto unlock; unmap: munmap(map, size); unlock: flock(fd, LOCK_UN); close: fdatasync(fd); close(fd); errno = -err; return err; } static char *read_key(const char *pathname, const char *key, int icase) { struct stat st; char *map, *off, *end, *str = NULL; off_t size; size_t len; int fd, err = 0; fd = open(pathname, O_RDONLY); if (fd < 0) return NULL; if (flock(fd, LOCK_SH) < 0) { err = -errno; goto close; } if (fstat(fd, &st) < 0) { err = -errno; goto unlock; } size = st.st_size; map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (!map || map == MAP_FAILED) { err = -errno; goto unlock; } len = strlen(key); off = find_key(map, size, key, len, icase); if (!off) { err = -EILSEQ; goto unmap; } end = strnpbrk(off, size - (map - off), "\r\n"); if (!end) { err = -EILSEQ; goto unmap; } str = malloc(end - off - len); if (!str) { err = -EILSEQ; goto unmap; } memset(str, 0, end - off - len); strncpy(str, off + len + 1, end - off - len - 1); unmap: munmap(map, size); unlock: flock(fd, LOCK_UN); close: close(fd); errno = -err; return str; } int textfile_put(const char *pathname, const char *key, const char *value) { return write_key(pathname, key, value, 0); } int textfile_caseput(const char *pathname, const char *key, const char *value) { return write_key(pathname, key, value, 1); } int textfile_del(const char *pathname, const char *key) { return write_key(pathname, key, NULL, 0); } int textfile_casedel(const char *pathname, const char *key) { return write_key(pathname, key, NULL, 1); } char *textfile_get(const char *pathname, const char *key) { return read_key(pathname, key, 0); } char *textfile_caseget(const char *pathname, const char *key) { return read_key(pathname, key, 1); } int textfile_foreach(const char *pathname, textfile_cb func, void *data) { struct stat st; char *map, *off, *end, *key, *value; off_t size; size_t len; int fd, err = 0; fd = open(pathname, O_RDONLY); if (fd < 0) return -errno; if (flock(fd, LOCK_SH) < 0) { err = -errno; goto close; } if (fstat(fd, &st) < 0) { err = -errno; goto unlock; } size = st.st_size; map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); if (!map || map == MAP_FAILED) { err = -errno; goto unlock; } off = map; while (size - (off - map) > 0) { end = strnpbrk(off, size - (off - map), " "); if (!end) { err = -EILSEQ; break; } len = end - off; key = malloc(len + 1); if (!key) { err = -errno; break; } memset(key, 0, len + 1); memcpy(key, off, len); off = end + 1; if (size - (off - map) < 0) { err = -EILSEQ; free(key); break; } end = strnpbrk(off, size - (off - map), "\r\n"); if (!end) { err = -EILSEQ; free(key); break; } len = end - off; value = malloc(len + 1); if (!value) { err = -errno; free(key); break; } memset(value, 0, len + 1); memcpy(value, off, len); func(key, value, data); free(key); free(value); off = end + 1; } munmap(map, size); unlock: flock(fd, LOCK_UN); close: close(fd); errno = -err; return 0; } bluez-4.101/src/oui.h0000644000000000000000000000167011376221745011277 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ char *ouitocomp(const char *oui); int oui2comp(const char *oui, char *comp, size_t size); bluez-4.101/src/glib-helper.c0000644000000000000000000001240411766125764012674 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include "btio.h" #include "glib-helper.h" char *bt_uuid2string(uuid_t *uuid) { gchar *str; uuid_t uuid128; unsigned int data0; unsigned short data1; unsigned short data2; unsigned short data3; unsigned int data4; unsigned short data5; if (!uuid) return NULL; switch (uuid->type) { case SDP_UUID16: sdp_uuid16_to_uuid128(&uuid128, uuid); break; case SDP_UUID32: sdp_uuid32_to_uuid128(&uuid128, uuid); break; case SDP_UUID128: memcpy(&uuid128, uuid, sizeof(uuid_t)); break; default: /* Type of UUID unknown */ return NULL; } memcpy(&data0, &uuid128.value.uuid128.data[0], 4); memcpy(&data1, &uuid128.value.uuid128.data[4], 2); memcpy(&data2, &uuid128.value.uuid128.data[6], 2); memcpy(&data3, &uuid128.value.uuid128.data[8], 2); memcpy(&data4, &uuid128.value.uuid128.data[10], 4); memcpy(&data5, &uuid128.value.uuid128.data[14], 2); str = g_try_malloc0(MAX_LEN_UUID_STR); if (!str) return NULL; sprintf(str, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x", g_ntohl(data0), g_ntohs(data1), g_ntohs(data2), g_ntohs(data3), g_ntohl(data4), g_ntohs(data5)); return str; } static struct { const char *name; uint16_t class; } bt_services[] = { { "vcp", VIDEO_CONF_SVCLASS_ID }, { "pbap", PBAP_SVCLASS_ID }, { "sap", SAP_SVCLASS_ID }, { "ftp", OBEX_FILETRANS_SVCLASS_ID }, { "bpp", BASIC_PRINTING_SVCLASS_ID }, { "bip", IMAGING_SVCLASS_ID }, { "synch", IRMC_SYNC_SVCLASS_ID }, { "dun", DIALUP_NET_SVCLASS_ID }, { "opp", OBEX_OBJPUSH_SVCLASS_ID }, { "fax", FAX_SVCLASS_ID }, { "spp", SERIAL_PORT_SVCLASS_ID }, { "hsp", HEADSET_SVCLASS_ID }, { "hfp", HANDSFREE_SVCLASS_ID }, { } }; static uint16_t name2class(const char *pattern) { int i; for (i = 0; bt_services[i].name; i++) { if (strcasecmp(bt_services[i].name, pattern) == 0) return bt_services[i].class; } return 0; } static inline gboolean is_uuid128(const char *string) { return (strlen(string) == 36 && string[8] == '-' && string[13] == '-' && string[18] == '-' && string[23] == '-'); } static int string2uuid16(uuid_t *uuid, const char *string) { int length = strlen(string); char *endptr = NULL; uint16_t u16; if (length != 4 && length != 6) return -EINVAL; u16 = strtol(string, &endptr, 16); if (endptr && *endptr == '\0') { sdp_uuid16_create(uuid, u16); return 0; } return -EINVAL; } char *bt_name2string(const char *pattern) { uuid_t uuid; uint16_t uuid16; int i; /* UUID 128 string format */ if (is_uuid128(pattern)) return g_strdup(pattern); /* Friendly service name format */ uuid16 = name2class(pattern); if (uuid16) goto proceed; /* HEX format */ uuid16 = strtol(pattern, NULL, 16); for (i = 0; bt_services[i].class; i++) { if (bt_services[i].class == uuid16) goto proceed; } return NULL; proceed: sdp_uuid16_create(&uuid, uuid16); return bt_uuid2string(&uuid); } int bt_string2uuid(uuid_t *uuid, const char *string) { uint32_t data0, data4; uint16_t data1, data2, data3, data5; if (is_uuid128(string) && sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx", &data0, &data1, &data2, &data3, &data4, &data5) == 6) { uint8_t val[16]; data0 = g_htonl(data0); data1 = g_htons(data1); data2 = g_htons(data2); data3 = g_htons(data3); data4 = g_htonl(data4); data5 = g_htons(data5); memcpy(&val[0], &data0, 4); memcpy(&val[4], &data1, 2); memcpy(&val[6], &data2, 2); memcpy(&val[8], &data3, 2); memcpy(&val[10], &data4, 4); memcpy(&val[14], &data5, 2); sdp_uuid128_create(uuid, val); return 0; } else { uint16_t class = name2class(string); if (class) { sdp_uuid16_create(uuid, class); return 0; } return string2uuid16(uuid, string); } } gchar *bt_list2string(GSList *list) { GSList *l; gchar *str, *tmp; if (!list) return NULL; str = g_strdup((const gchar *) list->data); for (l = list->next; l; l = l->next) { tmp = g_strconcat(str, " " , (const gchar *) l->data, NULL); g_free(str); str = tmp; } return str; } GSList *bt_string2list(const gchar *str) { GSList *l = NULL; gchar **uuids; int i = 0; if (!str) return NULL; /* FIXME: eglib doesn't support g_strsplit */ uuids = g_strsplit(str, " ", 0); if (!uuids) return NULL; while (uuids[i]) { l = g_slist_append(l, uuids[i]); i++; } g_free(uuids); return l; } bluez-4.101/src/bluetoothd.8.in0000644000000000000000000000555411272762165013207 00000000000000.\" .TH "BLUETOOTHD" "8" "March 2004" "Bluetooth daemon" "System management commands" .SH "NAME" bluetoothd \- Bluetooth daemon .SH "SYNOPSIS" .B bluetoothd [ .B \-n ] .SH "DESCRIPTION" This manual page documents briefly the .B bluetoothd daemon, which manages all the Bluetooth devices. .B bluetoothd itself does not accept many command\-line options, as most of its configuration is done in the .B @CONFIGDIR@/main.conf file, which has its own man page. .B bluetoothd can also provide a number of services via the D-Bus message bus system. .SH "OPTIONS" .TP .BI \-n Don't run as daemon in background. .TP .BI \-d Enable debug information output. .TP .BI \-m\ mtu\-size Use specific MTU size for SDP server. .SH "FILES" .TP .I @CONFIGDIR@/main.conf Default location of the global configuration file. .TP .I @STORAGEDIR@/nn:nn:nn:nn:nn:nn/linkkeys Default location for link keys of paired devices. The directory \fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP is the address of the local device. The file is line separated, with the following columns separated by whitespace: \fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address. \fInnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\fP Link key. \fIn\fP Link type integer. .TP .I @STORAGEDIR@/nn:nn:nn:nn:nn:nn/names Default location for the device name cache. The directory \fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP is the address of the local device. The file is line separated, with the following columns separated by whitespace: \fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address. \fIname\fP Remote device name, terminated with newline. .TP .I @STORAGEDIR@/nn:nn:nn:nn:nn:nn/features Default location for the features cache. The directory \fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP is the address of the local device. The file is line separated, with the following columns separated by whitespace: \fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address. \fInnnnnnnnnnnnnnnn\fP Remote device LMP features coded as an 8 byte bitfield. .TP .I @STORAGEDIR@/nn:nn:nn:nn:nn:nn/manufacturers Default location for the manufacturers cache. The directory \fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP is the address of the local device. The file is line separated, with the following columns separated by whitespace: \fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address. \fIn\fP Remote device manufacturer integer. \fIn\fP Remote device LMP version integer. \fIn\fP Remote device LMP sub-version integer. .SH "AUTHOR" This manual page was written by Marcel Holtmann, Philipp Matthias Hahn and Fredrik Noring. bluez-4.101/src/dbus-common.h0000644000000000000000000000317111766125764012733 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define MAX_PATH_LENGTH 64 void dict_append_entry(DBusMessageIter *dict, const char *key, int type, void *val); void dict_append_array(DBusMessageIter *dict, const char *key, int type, void *val, int n_elements); dbus_bool_t emit_property_changed(DBusConnection *conn, const char *path, const char *interface, const char *name, int type, void *value); dbus_bool_t emit_array_property_changed(DBusConnection *conn, const char *path, const char *interface, const char *name, int type, void *value, int num); void set_dbus_connection(DBusConnection *conn); DBusConnection *get_dbus_connection(void); const char *class_to_icon(uint32_t class); const char *gap_appearance_to_icon(uint16_t appearance); bluez-4.101/src/device.h0000644000000000000000000001362011766125764011747 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define DEVICE_INTERFACE "org.bluez.Device" struct btd_device; typedef enum { AUTH_TYPE_PINCODE, AUTH_TYPE_PASSKEY, AUTH_TYPE_CONFIRM, AUTH_TYPE_NOTIFY_PASSKEY, AUTH_TYPE_NOTIFY_PINCODE, } auth_type_t; struct btd_device *device_create(DBusConnection *conn, struct btd_adapter *adapter, const char *address, uint8_t bdaddr_type); void device_set_name(struct btd_device *device, const char *name); void device_get_name(struct btd_device *device, char *name, size_t len); uint16_t btd_device_get_vendor(struct btd_device *device); uint16_t btd_device_get_vendor_src(struct btd_device *device); uint16_t btd_device_get_product(struct btd_device *device); uint16_t btd_device_get_version(struct btd_device *device); void device_remove(struct btd_device *device, gboolean remove_stored); gint device_address_cmp(struct btd_device *device, const gchar *address); int device_browse_primary(struct btd_device *device, DBusConnection *conn, DBusMessage *msg, gboolean secure); int device_browse_sdp(struct btd_device *device, DBusConnection *conn, DBusMessage *msg, uuid_t *search, gboolean reverse); void device_probe_drivers(struct btd_device *device, GSList *profiles); const sdp_record_t *btd_device_get_record(struct btd_device *device, const char *uuid); GSList *btd_device_get_primaries(struct btd_device *device); void device_register_services(DBusConnection *conn, struct btd_device *device, GSList *prim_list, int psm); GSList *device_services_from_record(struct btd_device *device, GSList *profiles); void btd_device_add_uuid(struct btd_device *device, const char *uuid); struct btd_adapter *device_get_adapter(struct btd_device *device); void device_get_address(struct btd_device *device, bdaddr_t *bdaddr, uint8_t *bdaddr_type); void device_set_addr_type(struct btd_device *device, uint8_t bdaddr_type); uint8_t device_get_addr_type(struct btd_device *device); const gchar *device_get_path(struct btd_device *device); struct agent *device_get_agent(struct btd_device *device); gboolean device_is_bredr(struct btd_device *device); gboolean device_is_le(struct btd_device *device); gboolean device_is_busy(struct btd_device *device); gboolean device_is_temporary(struct btd_device *device); gboolean device_is_paired(struct btd_device *device); gboolean device_is_bonded(struct btd_device *device); gboolean device_is_trusted(struct btd_device *device); void device_set_paired(struct btd_device *device, gboolean paired); void device_set_temporary(struct btd_device *device, gboolean temporary); void device_set_bonded(struct btd_device *device, gboolean bonded); void device_set_auto_connect(struct btd_device *device, gboolean enable); gboolean device_is_connected(struct btd_device *device); DBusMessage *device_create_bonding(struct btd_device *device, DBusConnection *conn, DBusMessage *msg, const char *agent_path, uint8_t capability); void device_bonding_complete(struct btd_device *device, uint8_t status); void device_simple_pairing_complete(struct btd_device *device, uint8_t status); gboolean device_is_creating(struct btd_device *device, const char *sender); gboolean device_is_bonding(struct btd_device *device, const char *sender); void device_cancel_bonding(struct btd_device *device, uint8_t status); int device_request_authentication(struct btd_device *device, auth_type_t type, void *data, gboolean secure, void *cb); void device_cancel_authentication(struct btd_device *device, gboolean aborted); gboolean device_is_authenticating(struct btd_device *device); gboolean device_is_authorizing(struct btd_device *device); void device_set_authorizing(struct btd_device *device, gboolean auth); void device_add_connection(struct btd_device *device, DBusConnection *conn); void device_remove_connection(struct btd_device *device, DBusConnection *conn); void device_request_disconnect(struct btd_device *device, DBusMessage *msg); typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal, void *user_data); guint device_add_disconnect_watch(struct btd_device *device, disconnect_watch watch, void *user_data, GDestroyNotify destroy); void device_remove_disconnect_watch(struct btd_device *device, guint id); void device_set_class(struct btd_device *device, uint32_t value); #define BTD_UUIDS(args...) ((const char *[]) { args, NULL } ) struct btd_device_driver { const char *name; const char **uuids; int (*probe) (struct btd_device *device, GSList *uuids); void (*remove) (struct btd_device *device); }; int btd_register_device_driver(struct btd_device_driver *driver); void btd_unregister_device_driver(struct btd_device_driver *driver); struct btd_device *btd_device_ref(struct btd_device *device); void btd_device_unref(struct btd_device *device); int device_block(DBusConnection *conn, struct btd_device *device, gboolean update_only); int device_unblock(DBusConnection *conn, struct btd_device *device, gboolean silent, gboolean update_only); void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src, uint16_t vendor_id, uint16_t product_id, uint16_t product_ver); bluez-4.101/src/main.c0000644000000000000000000002744611766125764011442 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "log.h" #include "hcid.h" #include "sdpd.h" #include "adapter.h" #include "dbus-common.h" #include "agent.h" #include "manager.h" #define BLUEZ_NAME "org.bluez" #define LAST_ADAPTER_EXIT_TIMEOUT 30 #define DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */ #define DEFAULT_AUTO_CONNECT_TIMEOUT 60 /* 60 seconds */ struct main_opts main_opts; static GKeyFile *load_config(const char *file) { GError *err = NULL; GKeyFile *keyfile; keyfile = g_key_file_new(); g_key_file_set_list_separator(keyfile, ','); if (!g_key_file_load_from_file(keyfile, file, 0, &err)) { error("Parsing %s failed: %s", file, err->message); g_error_free(err); g_key_file_free(keyfile); return NULL; } return keyfile; } static void parse_did(const char *did) { int result; uint16_t vendor, product, version , source; /* version and source are optional */ version = 0x0000; source = 0x0002; result = sscanf(did, "bluetooth:%4hx:%4hx:%4hx", &vendor, &product, &version); if (result != EOF && result >= 2) { source = 0x0001; goto done; } result = sscanf(did, "usb:%4hx:%4hx:%4hx", &vendor, &product, &version); if (result != EOF && result >= 2) goto done; result = sscanf(did, "%4hx:%4hx:%4hx", &vendor, &product, &version); if (result == EOF || result < 2) return; done: main_opts.did_source = source; main_opts.did_vendor = vendor; main_opts.did_product = product; main_opts.did_version = version; } static void parse_config(GKeyFile *config) { GError *err = NULL; char *str; int val; gboolean boolean; if (!config) return; DBG("parsing main.conf"); val = g_key_file_get_integer(config, "General", "DiscoverableTimeout", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else { DBG("discovto=%d", val); main_opts.discovto = val; } val = g_key_file_get_integer(config, "General", "PairableTimeout", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else { DBG("pairto=%d", val); main_opts.pairto = val; } val = g_key_file_get_integer(config, "General", "PageTimeout", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else { DBG("pageto=%d", val); main_opts.pageto = val; main_opts.flags |= 1 << HCID_SET_PAGETO; } val = g_key_file_get_integer(config, "General", "AutoConnectTimeout", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else { DBG("auto_to=%d", val); main_opts.autoto = val; } str = g_key_file_get_string(config, "General", "Name", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else { DBG("name=%s", str); g_free(main_opts.name); main_opts.name = g_strdup(str); g_free(str); } str = g_key_file_get_string(config, "General", "Class", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else { DBG("class=%s", str); main_opts.class = strtol(str, NULL, 16); g_free(str); } boolean = g_key_file_get_boolean(config, "General", "InitiallyPowered", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else if (boolean == FALSE) main_opts.mode = MODE_OFF; boolean = g_key_file_get_boolean(config, "General", "RememberPowered", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else main_opts.remember_powered = boolean; str = g_key_file_get_string(config, "General", "DeviceID", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else { DBG("deviceid=%s", str); parse_did(str); g_free(str); } boolean = g_key_file_get_boolean(config, "General", "ReverseServiceDiscovery", &err); if (err) { DBG("%s", err->message); g_clear_error(&err); } else main_opts.reverse_sdp = boolean; boolean = g_key_file_get_boolean(config, "General", "NameResolving", &err); if (err) g_clear_error(&err); else main_opts.name_resolv = boolean; boolean = g_key_file_get_boolean(config, "General", "DebugKeys", &err); if (err) g_clear_error(&err); else main_opts.debug_keys = boolean; boolean = g_key_file_get_boolean(config, "General", "EnableGatt", &err); if (err) g_clear_error(&err); else main_opts.gatt_enabled = boolean; main_opts.link_mode = HCI_LM_ACCEPT; main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF | HCI_LP_HOLD | HCI_LP_PARK; } static void init_defaults(void) { /* Default HCId settings */ memset(&main_opts, 0, sizeof(main_opts)); main_opts.mode = MODE_CONNECTABLE; main_opts.name = g_strdup("BlueZ"); main_opts.discovto = DEFAULT_DISCOVERABLE_TIMEOUT; main_opts.autoto = DEFAULT_AUTO_CONNECT_TIMEOUT; main_opts.remember_powered = TRUE; main_opts.reverse_sdp = TRUE; main_opts.name_resolv = TRUE; if (gethostname(main_opts.host_name, sizeof(main_opts.host_name) - 1) < 0) strcpy(main_opts.host_name, "noname"); } static GMainLoop *event_loop; static unsigned int __terminated = 0; static gboolean signal_handler(GIOChannel *channel, GIOCondition cond, gpointer user_data) { struct signalfd_siginfo si; ssize_t result; int fd; if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) return FALSE; fd = g_io_channel_unix_get_fd(channel); result = read(fd, &si, sizeof(si)); if (result != sizeof(si)) return FALSE; switch (si.ssi_signo) { case SIGINT: case SIGTERM: if (__terminated == 0) { info("Terminating"); g_main_loop_quit(event_loop); } __terminated = 1; break; case SIGUSR2: __btd_toggle_debug(); break; case SIGPIPE: /* ignore */ break; } return TRUE; } static guint setup_signalfd(void) { GIOChannel *channel; guint source; sigset_t mask; int fd; sigemptyset(&mask); sigaddset(&mask, SIGINT); sigaddset(&mask, SIGTERM); sigaddset(&mask, SIGUSR2); sigaddset(&mask, SIGPIPE); if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) { perror("Failed to set signal mask"); return 0; } fd = signalfd(-1, &mask, 0); if (fd < 0) { perror("Failed to create signal descriptor"); return 0; } channel = g_io_channel_unix_new(fd); g_io_channel_set_close_on_unref(channel, TRUE); g_io_channel_set_encoding(channel, NULL, NULL); g_io_channel_set_buffered(channel, FALSE); source = g_io_add_watch(channel, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, signal_handler, NULL); g_io_channel_unref(channel); return source; } static gchar *option_debug = NULL; static gchar *option_plugin = NULL; static gchar *option_noplugin = NULL; static gboolean option_detach = TRUE; static gboolean option_version = FALSE; static gboolean option_udev = FALSE; static guint last_adapter_timeout = 0; static gboolean exit_timeout(gpointer data) { g_main_loop_quit(event_loop); last_adapter_timeout = 0; return FALSE; } void btd_start_exit_timer(void) { if (option_udev == FALSE) return; if (last_adapter_timeout > 0) g_source_remove(last_adapter_timeout); last_adapter_timeout = g_timeout_add_seconds(LAST_ADAPTER_EXIT_TIMEOUT, exit_timeout, NULL); } void btd_stop_exit_timer(void) { if (last_adapter_timeout == 0) return; g_source_remove(last_adapter_timeout); last_adapter_timeout = 0; } static void disconnect_dbus(void) { DBusConnection *conn = get_dbus_connection(); if (!conn || !dbus_connection_get_is_connected(conn)) return; manager_cleanup(conn, "/"); set_dbus_connection(NULL); dbus_connection_unref(conn); } static int connect_dbus(void) { DBusConnection *conn; DBusError err; dbus_error_init(&err); conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err); if (!conn) { if (dbus_error_is_set(&err)) { g_printerr("D-Bus setup failed: %s\n", err.message); dbus_error_free(&err); return -EIO; } return -EALREADY; } if (!manager_init(conn, "/")) return -EIO; set_dbus_connection(conn); return 0; } static gboolean parse_debug(const char *key, const char *value, gpointer user_data, GError **error) { if (value) option_debug = g_strdup(value); else option_debug = g_strdup("*"); return TRUE; } static GOptionEntry options[] = { { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK, parse_debug, "Specify debug options to enable", "DEBUG" }, { "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin, "Specify plugins to load", "NAME,..," }, { "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin, "Specify plugins not to load", "NAME,..." }, { "nodetach", 'n', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, &option_detach, "Don't run as daemon in background" }, { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version, "Show version information and exit" }, { "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev, "Run from udev mode of operation" }, { NULL }, }; int main(int argc, char *argv[]) { GOptionContext *context; GError *err = NULL; uint16_t mtu = 0; GKeyFile *config; guint signal; init_defaults(); context = g_option_context_new(NULL); g_option_context_add_main_entries(context, options, NULL); if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) { if (err != NULL) { g_printerr("%s\n", err->message); g_error_free(err); } else g_printerr("An unknown error occurred\n"); exit(1); } g_option_context_free(context); if (option_version == TRUE) { printf("%s\n", VERSION); exit(0); } if (option_udev == TRUE) { int err; option_detach = TRUE; err = connect_dbus(); if (err < 0) { if (err == -EALREADY) exit(0); exit(1); } } if (option_detach == TRUE && option_udev == FALSE) { if (daemon(0, 0)) { perror("Can't start daemon"); exit(1); } } umask(0077); event_loop = g_main_loop_new(NULL, FALSE); signal = setup_signalfd(); __btd_log_init(option_debug, option_detach); config = load_config(CONFIGDIR "/main.conf"); parse_config(config); agent_init(); if (option_udev == FALSE) { if (connect_dbus() < 0) { error("Unable to get on D-Bus"); exit(1); } } else { if (daemon(0, 0)) { perror("Can't start daemon"); exit(1); } } start_sdp_server(mtu, SDP_SERVER_COMPAT); /* Loading plugins has to be done after D-Bus has been setup since * the plugins might wanna expose some paths on the bus. However the * best order of how to init various subsystems of the Bluetooth * daemon needs to be re-worked. */ plugin_init(config, option_plugin, option_noplugin); if (adapter_ops_setup() < 0) { error("adapter_ops_setup failed"); exit(1); } rfkill_init(); DBG("Entering main loop"); g_main_loop_run(event_loop); g_source_remove(signal); disconnect_dbus(); rfkill_exit(); plugin_cleanup(); stop_sdp_server(); agent_exit(); g_main_loop_unref(event_loop); if (config) g_key_file_free(config); info("Exit"); __btd_log_cleanup(); return 0; } bluez-4.101/src/hcid.h0000644000000000000000000000326711766125764011425 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2000-2001 Qualcomm Incorporated * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ struct main_opts { char host_name[40]; unsigned long flags; char *name; uint32_t class; uint16_t pageto; uint16_t autoto; uint32_t discovto; uint32_t pairto; uint16_t link_mode; uint16_t link_policy; gboolean remember_powered; gboolean reverse_sdp; gboolean name_resolv; gboolean debug_keys; gboolean gatt_enabled; uint8_t mode; uint16_t did_source; uint16_t did_vendor; uint16_t did_product; uint16_t did_version; }; enum { HCID_SET_PAGETO, }; extern struct main_opts main_opts; void btd_start_exit_timer(void); void btd_stop_exit_timer(void); gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable); void plugin_cleanup(void); void rfkill_init(void); void rfkill_exit(void); bluez-4.101/src/attio.h0000644000000000000000000000236111766125764011630 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ typedef void (*attio_connect_cb) (GAttrib *attrib, gpointer user_data); typedef void (*attio_disconnect_cb) (gpointer user_data); guint btd_device_add_attio_callback(struct btd_device *device, attio_connect_cb cfunc, attio_disconnect_cb dcfunc, gpointer user_data); gboolean btd_device_remove_attio_callback(struct btd_device *device, guint id); bluez-4.101/src/sdpd-service.c0000644000000000000000000003416211766125764013077 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2001-2002 Nokia Corporation * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * Copyright (C) 2002-2003 Stephen Crane * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "hcid.h" #include "sdpd.h" #include "log.h" #include "adapter.h" #include "manager.h" static sdp_record_t *server = NULL; /* * List of version numbers supported by the SDP server. * Add to this list when newer versions are supported. */ static sdp_version_t sdpVnumArray[1] = { { 1, 0 } }; static const int sdpServerVnumEntries = 1; /* * A simple function which returns the time of day in * seconds. Used for updating the service db state * attribute of the service record of the SDP server */ uint32_t sdp_get_time(void) { /* * To handle failure in gettimeofday, so an old * value is returned and service does not fail */ static struct timeval tm; gettimeofday(&tm, NULL); return (uint32_t) tm.tv_sec; } /* * The service database state is an attribute of the service record * of the SDP server itself. This attribute is guaranteed to * change if any of the contents of the service repository * changes. This function updates the timestamp of value of * the svcDBState attribute * Set the SDP server DB. Simply a timestamp which is the marker * when the DB was modified. */ static void update_db_timestamp(void) { uint32_t dbts = sdp_get_time(); sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &dbts); sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d); } void register_public_browse_group(void) { sdp_list_t *browselist; uuid_t bgscid, pbgid; sdp_data_t *sdpdata; sdp_record_t *browse = sdp_record_alloc(); browse->handle = SDP_SERVER_RECORD_HANDLE + 1; sdp_record_add(BDADDR_ANY, browse); sdpdata = sdp_data_alloc(SDP_UINT32, &browse->handle); sdp_attr_add(browse, SDP_ATTR_RECORD_HANDLE, sdpdata); sdp_uuid16_create(&bgscid, BROWSE_GRP_DESC_SVCLASS_ID); browselist = sdp_list_append(0, &bgscid); sdp_set_service_classes(browse, browselist); sdp_list_free(browselist, 0); sdp_uuid16_create(&pbgid, PUBLIC_BROWSE_GROUP); sdp_attr_add_new(browse, SDP_ATTR_GROUP_ID, SDP_UUID16, &pbgid.value.uuid16); } /* * The SDP server must present its own service record to * the service repository. This can be accessed by service * discovery clients. This method constructs a service record * and stores it in the repository */ void register_server_service(void) { sdp_list_t *classIDList; uuid_t classID; void **versions, **versionDTDs; uint8_t dtd; sdp_data_t *pData; int i; server = sdp_record_alloc(); server->pattern = NULL; /* Force the record to be SDP_SERVER_RECORD_HANDLE */ server->handle = SDP_SERVER_RECORD_HANDLE; sdp_record_add(BDADDR_ANY, server); sdp_attr_add(server, SDP_ATTR_RECORD_HANDLE, sdp_data_alloc(SDP_UINT32, &server->handle)); sdp_uuid16_create(&classID, SDP_SERVER_SVCLASS_ID); classIDList = sdp_list_append(0, &classID); sdp_set_service_classes(server, classIDList); sdp_list_free(classIDList, 0); /* * Set the version numbers supported, these are passed as arguments * to the server on command line. Now defaults to 1.0 * Build the version number sequence first */ versions = malloc(sdpServerVnumEntries * sizeof(void *)); versionDTDs = malloc(sdpServerVnumEntries * sizeof(void *)); dtd = SDP_UINT16; for (i = 0; i < sdpServerVnumEntries; i++) { uint16_t *version = malloc(sizeof(uint16_t)); *version = sdpVnumArray[i].major; *version = (*version << 8); *version |= sdpVnumArray[i].minor; versions[i] = version; versionDTDs[i] = &dtd; } pData = sdp_seq_alloc(versionDTDs, versions, sdpServerVnumEntries); for (i = 0; i < sdpServerVnumEntries; i++) free(versions[i]); free(versions); free(versionDTDs); sdp_attr_add(server, SDP_ATTR_VERSION_NUM_LIST, pData); update_db_timestamp(); } void register_device_id(void) { const uint16_t spec = 0x0103; const uint8_t primary = 1; sdp_list_t *class_list, *group_list, *profile_list; uuid_t class_uuid, group_uuid; sdp_data_t *sdp_data, *primary_data, *source_data; sdp_data_t *spec_data, *vendor_data, *product_data, *version_data; sdp_profile_desc_t profile; sdp_record_t *record = sdp_record_alloc(); info("Adding device id record for %04x:%04x:%04x:%04x", main_opts.did_source, main_opts.did_vendor, main_opts.did_product, main_opts.did_version); record->handle = sdp_next_handle(); sdp_record_add(BDADDR_ANY, record); sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle); sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data); sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID); class_list = sdp_list_append(0, &class_uuid); sdp_set_service_classes(record, class_list); sdp_list_free(class_list, NULL); sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP); group_list = sdp_list_append(NULL, &group_uuid); sdp_set_browse_groups(record, group_list); sdp_list_free(group_list, NULL); sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID); profile.version = spec; profile_list = sdp_list_append(NULL, &profile); sdp_set_profile_descs(record, profile_list); sdp_list_free(profile_list, NULL); spec_data = sdp_data_alloc(SDP_UINT16, &spec); sdp_attr_add(record, 0x0200, spec_data); vendor_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_vendor); sdp_attr_add(record, 0x0201, vendor_data); product_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_product); sdp_attr_add(record, 0x0202, product_data); version_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_version); sdp_attr_add(record, 0x0203, version_data); primary_data = sdp_data_alloc(SDP_BOOL, &primary); sdp_attr_add(record, 0x0204, primary_data); source_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_source); sdp_attr_add(record, 0x0205, source_data); update_db_timestamp(); } int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec) { sdp_data_t *data; sdp_list_t *pattern; if (rec->handle == 0xffffffff) { rec->handle = sdp_next_handle(); if (rec->handle < 0x10000) return -ENOSPC; } else { if (sdp_record_find(rec->handle)) return -EEXIST; } DBG("Adding record with handle 0x%05x", rec->handle); sdp_record_add(src, rec); data = sdp_data_alloc(SDP_UINT32, &rec->handle); sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data); if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) { uuid_t uuid; sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); sdp_pattern_add_uuid(rec, &uuid); } for (pattern = rec->pattern; pattern; pattern = pattern->next) { char uuid[32]; if (pattern->data == NULL) continue; sdp_uuid2strn((uuid_t *) pattern->data, uuid, sizeof(uuid)); DBG("Record pattern UUID %s", uuid); } update_db_timestamp(); return 0; } int remove_record_from_server(uint32_t handle) { sdp_record_t *rec; /* Refuse to remove the server's own record */ if (handle == SDP_SERVER_RECORD_HANDLE) return -EINVAL; DBG("Removing record with handle 0x%05x", handle); rec = sdp_record_find(handle); if (!rec) return -ENOENT; if (sdp_record_remove(handle) == 0) update_db_timestamp(); sdp_record_free(rec); return 0; } /* FIXME: refactor for server-side */ static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p, unsigned int bufsize, uint32_t handleExpected, int *scanned) { int extractStatus = -1, localExtractedLength = 0; uint8_t dtd; int seqlen = 0; sdp_record_t *rec = NULL; uint16_t attrId, lookAheadAttrId; sdp_data_t *pAttr = NULL; uint32_t handle = 0xffffffff; *scanned = sdp_extract_seqtype(p, bufsize, &dtd, &seqlen); p += *scanned; bufsize -= *scanned; if (bufsize < sizeof(uint8_t) + sizeof(uint8_t)) { SDPDBG("Unexpected end of packet"); return NULL; } lookAheadAttrId = ntohs(bt_get_unaligned((uint16_t *) (p + sizeof(uint8_t)))); SDPDBG("Look ahead attr id : %d", lookAheadAttrId); if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) { if (bufsize < (sizeof(uint8_t) * 2) + sizeof(uint16_t) + sizeof(uint32_t)) { SDPDBG("Unexpected end of packet"); return NULL; } handle = ntohl(bt_get_unaligned((uint32_t *) (p + sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint8_t)))); SDPDBG("SvcRecHandle : 0x%x", handle); rec = sdp_record_find(handle); } else if (handleExpected != 0xffffffff) rec = sdp_record_find(handleExpected); if (!rec) { rec = sdp_record_alloc(); rec->attrlist = NULL; if (lookAheadAttrId == SDP_ATTR_RECORD_HANDLE) { rec->handle = handle; sdp_record_add(device, rec); } else if (handleExpected != 0xffffffff) { rec->handle = handleExpected; sdp_record_add(device, rec); } } else { sdp_list_free(rec->attrlist, (sdp_free_func_t) sdp_data_free); rec->attrlist = NULL; } while (localExtractedLength < seqlen) { int attrSize = sizeof(uint8_t); int attrValueLength = 0; if (bufsize < attrSize + sizeof(uint16_t)) { SDPDBG("Unexpected end of packet: Terminating extraction of attributes"); break; } SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d", seqlen, localExtractedLength); dtd = *(uint8_t *) p; attrId = ntohs(bt_get_unaligned((uint16_t *) (p + attrSize))); attrSize += sizeof(uint16_t); SDPDBG("DTD of attrId : %d Attr id : 0x%x", dtd, attrId); pAttr = sdp_extract_attr(p + attrSize, bufsize - attrSize, &attrValueLength, rec); SDPDBG("Attr id : 0x%x attrValueLength : %d", attrId, attrValueLength); attrSize += attrValueLength; if (pAttr == NULL) { SDPDBG("Terminating extraction of attributes"); break; } localExtractedLength += attrSize; p += attrSize; bufsize -= attrSize; sdp_attr_replace(rec, attrId, pAttr); extractStatus = 0; SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d", seqlen, localExtractedLength); } if (extractStatus == 0) { SDPDBG("Successful extracting of Svc Rec attributes"); #ifdef SDP_DEBUG sdp_print_service_attr(rec->attrlist); #endif *scanned += seqlen; } return rec; } /* * Add the newly created service record to the service repository */ int service_register_req(sdp_req_t *req, sdp_buf_t *rsp) { int scanned = 0; sdp_data_t *handle; uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t); int bufsize = req->len - sizeof(sdp_pdu_hdr_t); sdp_record_t *rec; req->flags = *p++; if (req->flags & SDP_DEVICE_RECORD) { bacpy(&req->device, (bdaddr_t *) p); p += sizeof(bdaddr_t); bufsize -= sizeof(bdaddr_t); } /* save image of PDU: we need it when clients request this attribute */ rec = extract_pdu_server(&req->device, p, bufsize, 0xffffffff, &scanned); if (!rec) goto invalid; if (rec->handle == 0xffffffff) { rec->handle = sdp_next_handle(); if (rec->handle < 0x10000) { sdp_record_free(rec); goto invalid; } } else { if (sdp_record_find(rec->handle)) { /* extract_pdu_server will add the record handle * if it is missing. So instead of failing, skip * the record adding to avoid duplication. */ goto success; } } sdp_record_add(&req->device, rec); if (!(req->flags & SDP_RECORD_PERSIST)) sdp_svcdb_set_collectable(rec, req->sock); handle = sdp_data_alloc(SDP_UINT32, &rec->handle); sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle); success: /* if the browse group descriptor is NULL, * ensure that the record belongs to the ROOT group */ if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) { uuid_t uuid; sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); sdp_pattern_add_uuid(rec, &uuid); } update_db_timestamp(); /* Build a rsp buffer */ bt_put_unaligned(htonl(rec->handle), (uint32_t *) rsp->data); rsp->data_size = sizeof(uint32_t); return 0; invalid: bt_put_unaligned(htons(SDP_INVALID_SYNTAX), (uint16_t *) rsp->data); rsp->data_size = sizeof(uint16_t); return -1; } /* * Update a service record */ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp) { sdp_record_t *orec, *nrec; int status = 0, scanned = 0; uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t); int bufsize = req->len - sizeof(sdp_pdu_hdr_t); uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p)); SDPDBG("Svc Rec Handle: 0x%x", handle); p += sizeof(uint32_t); bufsize -= sizeof(uint32_t); orec = sdp_record_find(handle); SDPDBG("SvcRecOld: %p", orec); if (!orec) { status = SDP_INVALID_RECORD_HANDLE; goto done; } nrec = extract_pdu_server(BDADDR_ANY, p, bufsize, handle, &scanned); if (!nrec) { status = SDP_INVALID_SYNTAX; goto done; } assert(nrec == orec); update_db_timestamp(); done: p = rsp->data; bt_put_unaligned(htons(status), (uint16_t *) p); rsp->data_size = sizeof(uint16_t); return status; } /* * Remove a registered service record */ int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp) { uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t); uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p)); sdp_record_t *rec; int status = 0; /* extract service record handle */ rec = sdp_record_find(handle); if (rec) { sdp_svcdb_collect(rec); status = sdp_record_remove(handle); sdp_record_free(rec); if (status == 0) update_db_timestamp(); } else { status = SDP_INVALID_RECORD_HANDLE; SDPDBG("Could not find record : 0x%x", handle); } p = rsp->data; bt_put_unaligned(htons(status), (uint16_t *) p); rsp->data_size = sizeof(uint16_t); return status; } bluez-4.101/src/manager.h0000644000000000000000000000324211766125764012121 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #define MANAGER_INTERFACE "org.bluez.Manager" typedef void (*adapter_cb) (struct btd_adapter *adapter, gpointer user_data); dbus_bool_t manager_init(DBusConnection *conn, const char *path); void manager_cleanup(DBusConnection *conn, const char *path); const char *manager_get_base_path(void); struct btd_adapter *manager_find_adapter(const bdaddr_t *sba); struct btd_adapter *manager_find_adapter_by_id(int id); struct btd_adapter *manager_get_default_adapter(void); void manager_foreach_adapter(adapter_cb func, gpointer user_data); GSList *manager_get_adapters(void); struct btd_adapter *btd_manager_register_adapter(int id, gboolean up); int btd_manager_unregister_adapter(int id); void manager_add_adapter(const char *path); bluez-4.101/src/dbus-common.c0000644000000000000000000001421411766125764012726 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2005-2007 Johan Hedberg * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "log.h" #include "dbus-common.h" static DBusConnection *connection = NULL; static void append_variant(DBusMessageIter *iter, int type, void *val) { DBusMessageIter value; char sig[2] = { type, '\0' }; dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value); dbus_message_iter_append_basic(&value, type, val); dbus_message_iter_close_container(iter, &value); } static void append_array_variant(DBusMessageIter *iter, int type, void *val, int n_elements) { DBusMessageIter variant, array; char type_sig[2] = { type, '\0' }; char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' }; dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, array_sig, &variant); dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, type_sig, &array); if (dbus_type_is_fixed(type) == TRUE) { dbus_message_iter_append_fixed_array(&array, type, val, n_elements); } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) { const char ***str_array = val; int i; for (i = 0; i < n_elements; i++) dbus_message_iter_append_basic(&array, type, &((*str_array)[i])); } dbus_message_iter_close_container(&variant, &array); dbus_message_iter_close_container(iter, &variant); } void dict_append_entry(DBusMessageIter *dict, const char *key, int type, void *val) { DBusMessageIter entry; if (type == DBUS_TYPE_STRING) { const char *str = *((const char **) val); if (str == NULL) return; } dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); append_variant(&entry, type, val); dbus_message_iter_close_container(dict, &entry); } void dict_append_array(DBusMessageIter *dict, const char *key, int type, void *val, int n_elements) { DBusMessageIter entry; dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); append_array_variant(&entry, type, val, n_elements); dbus_message_iter_close_container(dict, &entry); } dbus_bool_t emit_property_changed(DBusConnection *conn, const char *path, const char *interface, const char *name, int type, void *value) { DBusMessage *signal; DBusMessageIter iter; signal = dbus_message_new_signal(path, interface, "PropertyChanged"); if (!signal) { error("Unable to allocate new %s.PropertyChanged signal", interface); return FALSE; } dbus_message_iter_init_append(signal, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); append_variant(&iter, type, value); return g_dbus_send_message(conn, signal); } dbus_bool_t emit_array_property_changed(DBusConnection *conn, const char *path, const char *interface, const char *name, int type, void *value, int num) { DBusMessage *signal; DBusMessageIter iter; signal = dbus_message_new_signal(path, interface, "PropertyChanged"); if (!signal) { error("Unable to allocate new %s.PropertyChanged signal", interface); return FALSE; } dbus_message_iter_init_append(signal, &iter); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); append_array_variant(&iter, type, value, num); return g_dbus_send_message(conn, signal); } void set_dbus_connection(DBusConnection *conn) { connection = conn; } DBusConnection *get_dbus_connection(void) { return connection; } const char *class_to_icon(uint32_t class) { switch ((class & 0x1f00) >> 8) { case 0x01: return "computer"; case 0x02: switch ((class & 0xfc) >> 2) { case 0x01: case 0x02: case 0x03: case 0x05: return "phone"; case 0x04: return "modem"; } break; case 0x03: return "network-wireless"; case 0x04: switch ((class & 0xfc) >> 2) { case 0x01: case 0x02: return "audio-card"; /* Headset */ case 0x06: return "audio-card"; /* Headphone */ case 0x0b: /* VCR */ case 0x0c: /* Video Camera */ case 0x0d: /* Camcorder */ return "camera-video"; default: return "audio-card"; /* Other audio device */ } break; case 0x05: switch ((class & 0xc0) >> 6) { case 0x00: switch ((class & 0x1e) >> 2) { case 0x01: case 0x02: return "input-gaming"; } break; case 0x01: return "input-keyboard"; case 0x02: switch ((class & 0x1e) >> 2) { case 0x05: return "input-tablet"; default: return "input-mouse"; } } break; case 0x06: if (class & 0x80) return "printer"; if (class & 0x20) return "camera-photo"; break; } return NULL; } const char *gap_appearance_to_icon(uint16_t appearance) { switch ((appearance & 0xffc0) >> 6) { case 0x01: return "phone"; case 0x02: return "computer"; case 0x05: return "video-display"; case 0x0a: return "multimedia-player"; case 0x0b: return "scanner"; case 0x0f: /* HID Generic */ switch (appearance & 0x3f) { case 0x01: return "input-keyboard"; case 0x02: return "input-mouse"; case 0x03: case 0x04: return "input-gaming"; case 0x05: return "input-tablet"; case 0x08: return "scanner"; } break; } return NULL; } bluez-4.101/src/sdp-xml.c0000644000000000000000000004026711571052274012063 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2005-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "sdp-xml.h" #define STRBUFSIZE 1024 #define MAXINDENT 64 static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level, void *data, void (*appender)(void *, const char *)) { int i, hex; char buf[STRBUFSIZE]; char indent[MAXINDENT]; if (!value) return; if (indent_level >= MAXINDENT) indent_level = MAXINDENT - 2; for (i = 0; i < indent_level; i++) indent[i] = '\t'; indent[i] = '\0'; buf[STRBUFSIZE - 1] = '\0'; switch (value->dtd) { case SDP_DATA_NIL: appender(data, indent); appender(data, "\n"); break; case SDP_BOOL: appender(data, indent); appender(data, "val.uint8 ? "true" : "false"); appender(data, "\" />\n"); break; case SDP_UINT8: appender(data, indent); appender(data, "val.uint8); appender(data, buf); appender(data, "\" />\n"); break; case SDP_UINT16: appender(data, indent); appender(data, "val.uint16); appender(data, buf); appender(data, "\" />\n"); break; case SDP_UINT32: appender(data, indent); appender(data, "val.uint32); appender(data, buf); appender(data, "\" />\n"); break; case SDP_UINT64: appender(data, indent); appender(data, "val.uint64); appender(data, buf); appender(data, "\" />\n"); break; case SDP_UINT128: appender(data, indent); appender(data, "val.uint128.data[i]); } appender(data, buf); appender(data, "\" />\n"); break; case SDP_INT8: appender(data, indent); appender(data, "val.int8); appender(data, buf); appender(data, "\" />\n"); break; case SDP_INT16: appender(data, indent); appender(data, "val.int16); appender(data, buf); appender(data, "\" />\n"); break; case SDP_INT32: appender(data, indent); appender(data, "val.int32); appender(data, buf); appender(data, "\" />\n"); break; case SDP_INT64: appender(data, indent); appender(data, "val.int64); appender(data, buf); appender(data, "\" />\n"); break; case SDP_INT128: appender(data, indent); appender(data, "val.int128.data[i]); } appender(data, buf); appender(data, "\" />\n"); break; case SDP_UUID16: appender(data, indent); appender(data, "val.uuid.value.uuid16); appender(data, buf); appender(data, "\" />\n"); break; case SDP_UUID32: appender(data, indent); appender(data, "val.uuid.value.uuid32); appender(data, buf); appender(data, "\" />\n"); break; case SDP_UUID128: appender(data, indent); appender(data, "val.uuid.value. uuid128.data[0], (unsigned char) value->val.uuid.value. uuid128.data[1], (unsigned char) value->val.uuid.value. uuid128.data[2], (unsigned char) value->val.uuid.value. uuid128.data[3], (unsigned char) value->val.uuid.value. uuid128.data[4], (unsigned char) value->val.uuid.value. uuid128.data[5], (unsigned char) value->val.uuid.value. uuid128.data[6], (unsigned char) value->val.uuid.value. uuid128.data[7], (unsigned char) value->val.uuid.value. uuid128.data[8], (unsigned char) value->val.uuid.value. uuid128.data[9], (unsigned char) value->val.uuid.value. uuid128.data[10], (unsigned char) value->val.uuid.value. uuid128.data[11], (unsigned char) value->val.uuid.value. uuid128.data[12], (unsigned char) value->val.uuid.value. uuid128.data[13], (unsigned char) value->val.uuid.value. uuid128.data[14], (unsigned char) value->val.uuid.value. uuid128.data[15]); appender(data, buf); appender(data, "\" />\n"); break; case SDP_TEXT_STR8: case SDP_TEXT_STR16: case SDP_TEXT_STR32: { int num_chars_to_escape = 0; int length = value->unitSize - 1; char *strBuf = 0; hex = 0; for (i = 0; i < length; i++) { if (!isprint(value->val.str[i]) && value->val.str[i] != '\0') { hex = 1; break; } /* XML is evil, must do this... */ if ((value->val.str[i] == '<') || (value->val.str[i] == '>') || (value->val.str[i] == '"') || (value->val.str[i] == '&')) num_chars_to_escape++; } appender(data, indent); appender(data, "unitSize-1) * 2 + 1)); /* Unit Size seems to include the size for dtd It is thus off by 1 This is safe for Normal strings, but not hex encoded data */ for (i = 0; i < (value->unitSize-1); i++) sprintf(&strBuf[i*sizeof(char)*2], "%02x", (unsigned char) value->val.str[i]); strBuf[(value->unitSize-1) * 2] = '\0'; } else { int j; /* escape the XML disallowed chars */ strBuf = malloc(sizeof(char) * (value->unitSize + 1 + num_chars_to_escape * 4)); for (i = 0, j = 0; i < length; i++) { if (value->val.str[i] == '&') { strBuf[j++] = '&'; strBuf[j++] = 'a'; strBuf[j++] = 'm'; strBuf[j++] = 'p'; } else if (value->val.str[i] == '<') { strBuf[j++] = '&'; strBuf[j++] = 'l'; strBuf[j++] = 't'; } else if (value->val.str[i] == '>') { strBuf[j++] = '&'; strBuf[j++] = 'g'; strBuf[j++] = 't'; } else if (value->val.str[i] == '"') { strBuf[j++] = '&'; strBuf[j++] = 'q'; strBuf[j++] = 'u'; strBuf[j++] = 'o'; strBuf[j++] = 't'; } else if (value->val.str[i] == '\0') { strBuf[j++] = ' '; } else { strBuf[j++] = value->val.str[i]; } } strBuf[j] = '\0'; } appender(data, "value=\""); appender(data, strBuf); appender(data, "\" />\n"); free(strBuf); break; } case SDP_URL_STR8: case SDP_URL_STR16: case SDP_URL_STR32: { char *strBuf; appender(data, indent); appender(data, "val.str, value->unitSize - 1); appender(data, strBuf); free(strBuf); appender(data, "\" />\n"); break; } case SDP_SEQ8: case SDP_SEQ16: case SDP_SEQ32: appender(data, indent); appender(data, "\n"); convert_raw_data_to_xml(value->val.dataseq, indent_level + 1, data, appender); appender(data, indent); appender(data, "\n"); break; case SDP_ALT8: case SDP_ALT16: case SDP_ALT32: appender(data, indent); appender(data, "\n"); convert_raw_data_to_xml(value->val.dataseq, indent_level + 1, data, appender); appender(data, indent); appender(data, "\n"); break; } convert_raw_data_to_xml(value->next, indent_level, data, appender); } struct conversion_data { void *data; void (*appender)(void *data, const char *); }; static void convert_raw_attr_to_xml_func(void *val, void *data) { struct conversion_data *cd = data; sdp_data_t *value = val; char buf[STRBUFSIZE]; buf[STRBUFSIZE - 1] = '\0'; snprintf(buf, STRBUFSIZE - 1, "\t\n", value->attrId); cd->appender(cd->data, buf); if (data) convert_raw_data_to_xml(value, 2, cd->data, cd->appender); else cd->appender(cd->data, "\t\tNULL\n"); cd->appender(cd->data, "\t\n"); } /* * Will convert the sdp record to XML. The appender and data can be used * to control where to output the record (e.g. file or a data buffer). The * appender will be called repeatedly with data and the character buffer * (containing parts of the generated XML) to append. */ void convert_sdp_record_to_xml(sdp_record_t *rec, void *data, void (*appender)(void *, const char *)) { struct conversion_data cd; cd.data = data; cd.appender = appender; if (rec && rec->attrlist) { appender(data, "\n\n"); appender(data, "\n"); sdp_list_foreach(rec->attrlist, convert_raw_attr_to_xml_func, &cd); appender(data, "\n"); } } static sdp_data_t *sdp_xml_parse_uuid128(const char *data) { uint128_t val; unsigned int i, j; char buf[3]; memset(&val, 0, sizeof(val)); buf[2] = '\0'; for (j = 0, i = 0; i < strlen(data);) { if (data[i] == '-') { i++; continue; } buf[0] = data[i]; buf[1] = data[i + 1]; val.data[j++] = strtoul(buf, 0, 16); i += 2; } return sdp_data_alloc(SDP_UUID128, &val); } sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record) { sdp_data_t *ret; char *endptr; uint32_t val; uint16_t val2; int len; len = strlen(data); if (len == 36) { ret = sdp_xml_parse_uuid128(data); goto result; } val = strtoll(data, &endptr, 16); /* Couldn't parse */ if (*endptr != '\0') return NULL; if (val > USHRT_MAX) { ret = sdp_data_alloc(SDP_UUID32, &val); goto result; } val2 = val; ret = sdp_data_alloc(SDP_UUID16, &val2); result: if (record && ret) sdp_pattern_add_uuid(record, &ret->val.uuid); return ret; } sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd) { char *endptr; sdp_data_t *ret = NULL; switch (dtd) { case SDP_BOOL: { uint8_t val = 0; if (!strcmp("true", data)) { val = 1; } else if (!strcmp("false", data)) { val = 0; } else { return NULL; } ret = sdp_data_alloc(dtd, &val); break; } case SDP_INT8: { int8_t val = strtoul(data, &endptr, 0); /* Failed to parse */ if ((endptr != data) && (*endptr != '\0')) return NULL; ret = sdp_data_alloc(dtd, &val); break; } case SDP_UINT8: { uint8_t val = strtoul(data, &endptr, 0); /* Failed to parse */ if ((endptr != data) && (*endptr != '\0')) return NULL; ret = sdp_data_alloc(dtd, &val); break; } case SDP_INT16: { int16_t val = strtoul(data, &endptr, 0); /* Failed to parse */ if ((endptr != data) && (*endptr != '\0')) return NULL; ret = sdp_data_alloc(dtd, &val); break; } case SDP_UINT16: { uint16_t val = strtoul(data, &endptr, 0); /* Failed to parse */ if ((endptr != data) && (*endptr != '\0')) return NULL; ret = sdp_data_alloc(dtd, &val); break; } case SDP_INT32: { int32_t val = strtoul(data, &endptr, 0); /* Failed to parse */ if ((endptr != data) && (*endptr != '\0')) return NULL; ret = sdp_data_alloc(dtd, &val); break; } case SDP_UINT32: { uint32_t val = strtoul(data, &endptr, 0); /* Failed to parse */ if ((endptr != data) && (*endptr != '\0')) return NULL; ret = sdp_data_alloc(dtd, &val); break; } case SDP_INT64: { int64_t val = strtoull(data, &endptr, 0); /* Failed to parse */ if ((endptr != data) && (*endptr != '\0')) return NULL; ret = sdp_data_alloc(dtd, &val); break; } case SDP_UINT64: { uint64_t val = strtoull(data, &endptr, 0); /* Failed to parse */ if ((endptr != data) && (*endptr != '\0')) return NULL; ret = sdp_data_alloc(dtd, &val); break; } case SDP_INT128: case SDP_UINT128: { uint128_t val; int i = 0; char buf[3]; buf[2] = '\0'; for (; i < 32; i += 2) { buf[0] = data[i]; buf[1] = data[i + 1]; val.data[i >> 1] = strtoul(buf, 0, 16); } ret = sdp_data_alloc(dtd, &val); break; } }; return ret; } static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length) { int len = strlen(data); char *text; if (encoding == SDP_XML_ENCODING_NORMAL) { text = strdup(data); *length = len; } else { char buf[3], *decoded; int i; decoded = malloc((len >> 1) + 1); /* Ensure the string is a power of 2 */ len = (len >> 1) << 1; buf[2] = '\0'; for (i = 0; i < len; i += 2) { buf[0] = data[i]; buf[1] = data[i + 1]; decoded[i >> 1] = strtoul(buf, 0, 16); } decoded[len >> 1] = '\0'; text = decoded; *length = len >> 1; } return text; } sdp_data_t *sdp_xml_parse_url(const char *data) { uint8_t dtd = SDP_URL_STR8; char *url; uint32_t length; sdp_data_t *ret; url = sdp_xml_parse_string_decode(data, SDP_XML_ENCODING_NORMAL, &length); if (length > UCHAR_MAX) dtd = SDP_URL_STR16; ret = sdp_data_alloc_with_length(dtd, url, length); free(url); return ret; } sdp_data_t *sdp_xml_parse_text(const char *data, char encoding) { uint8_t dtd = SDP_TEXT_STR8; char *text; uint32_t length; sdp_data_t *ret; text = sdp_xml_parse_string_decode(data, encoding, &length); if (length > UCHAR_MAX) dtd = SDP_TEXT_STR16; ret = sdp_data_alloc_with_length(dtd, text, length); free(text); return ret; } sdp_data_t *sdp_xml_parse_nil(const char *data) { return sdp_data_alloc(SDP_DATA_NIL, 0); } #define DEFAULT_XML_DATA_SIZE 1024 struct sdp_xml_data *sdp_xml_data_alloc(void) { struct sdp_xml_data *elem; elem = malloc(sizeof(struct sdp_xml_data)); if (!elem) return NULL; memset(elem, 0, sizeof(struct sdp_xml_data)); /* Null terminate the text */ elem->size = DEFAULT_XML_DATA_SIZE; elem->text = malloc(DEFAULT_XML_DATA_SIZE); elem->text[0] = '\0'; return elem; } void sdp_xml_data_free(struct sdp_xml_data *elem) { if (elem->data) sdp_data_free(elem->data); free(elem->name); free(elem->text); free(elem); } struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem) { char *newbuf; newbuf = malloc(elem->size * 2); if (!newbuf) return NULL; memcpy(newbuf, elem->text, elem->size); elem->size *= 2; free(elem->text); elem->text = newbuf; return elem; } sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem, sdp_record_t *record) { const char *data = elem->text; if (!strcmp(el, "boolean")) return sdp_xml_parse_int(data, SDP_BOOL); else if (!strcmp(el, "uint8")) return sdp_xml_parse_int(data, SDP_UINT8); else if (!strcmp(el, "uint16")) return sdp_xml_parse_int(data, SDP_UINT16); else if (!strcmp(el, "uint32")) return sdp_xml_parse_int(data, SDP_UINT32); else if (!strcmp(el, "uint64")) return sdp_xml_parse_int(data, SDP_UINT64); else if (!strcmp(el, "uint128")) return sdp_xml_parse_int(data, SDP_UINT128); else if (!strcmp(el, "int8")) return sdp_xml_parse_int(data, SDP_INT8); else if (!strcmp(el, "int16")) return sdp_xml_parse_int(data, SDP_INT16); else if (!strcmp(el, "int32")) return sdp_xml_parse_int(data, SDP_INT32); else if (!strcmp(el, "int64")) return sdp_xml_parse_int(data, SDP_INT64); else if (!strcmp(el, "int128")) return sdp_xml_parse_int(data, SDP_INT128); else if (!strcmp(el, "uuid")) return sdp_xml_parse_uuid(data, record); else if (!strcmp(el, "url")) return sdp_xml_parse_url(data); else if (!strcmp(el, "text")) return sdp_xml_parse_text(data, elem->type); else if (!strcmp(el, "nil")) return sdp_xml_parse_nil(data); return NULL; } bluez-4.101/src/sdpd.h0000644000000000000000000000513511766125764011444 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2001-2002 Nokia Corporation * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * Copyright (C) 2002-2003 Stephen Crane * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #include #ifdef SDP_DEBUG #include #define SDPDBG(fmt, arg...) syslog(LOG_DEBUG, "%s: " fmt "\n", __func__ , ## arg) #else #define SDPDBG(fmt...) #endif typedef struct request { bdaddr_t device; bdaddr_t bdaddr; int local; int sock; int mtu; int flags; uint8_t *buf; int len; } sdp_req_t; void handle_request(int sk, uint8_t *data, int len); int service_register_req(sdp_req_t *req, sdp_buf_t *rsp); int service_update_req(sdp_req_t *req, sdp_buf_t *rsp); int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp); void register_public_browse_group(void); void register_server_service(void); void register_device_id(void); int record_sort(const void *r1, const void *r2); void sdp_svcdb_reset(void); void sdp_svcdb_collect_all(int sock); void sdp_svcdb_set_collectable(sdp_record_t *rec, int sock); void sdp_svcdb_collect(sdp_record_t *rec); sdp_record_t *sdp_record_find(uint32_t handle); void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec); int sdp_record_remove(uint32_t handle); sdp_list_t *sdp_get_record_list(void); sdp_list_t *sdp_get_access_list(void); int sdp_check_access(uint32_t handle, bdaddr_t *device); uint32_t sdp_next_handle(void); uint32_t sdp_get_time(void); #define SDP_SERVER_COMPAT (1 << 0) #define SDP_SERVER_MASTER (1 << 1) int start_sdp_server(uint16_t mtu, uint32_t flags); void stop_sdp_server(void); int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec); int remove_record_from_server(uint32_t handle); void sdp_init_services_list(bdaddr_t *device); bluez-4.101/src/oob.h0000644000000000000000000000220211571052274011246 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 ST-Ericsson SA * * Author: Szymon Janc for ST-Ericsson * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ typedef void (*oob_read_cb_t) (struct btd_adapter *adapter, uint8_t *hash, uint8_t *randomizer); void oob_register_cb(oob_read_cb_t cb); void oob_read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash, uint8_t *randomizer); bluez-4.101/src/bluetooth.ver0000644000000000000000000000011211571052274013037 00000000000000{ global: btd_*; g_dbus_*; info; error; debug; local: *; }; bluez-4.101/src/textfile.h0000644000000000000000000000323111571052274012316 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __TEXTFILE_H #define __TEXTFILE_H int create_dirs(const char *filename, const mode_t mode); int create_file(const char *filename, const mode_t mode); int create_name(char *buf, size_t size, const char *path, const char *address, const char *name); int textfile_put(const char *pathname, const char *key, const char *value); int textfile_caseput(const char *pathname, const char *key, const char *value); int textfile_del(const char *pathname, const char *key); int textfile_casedel(const char *pathname, const char *key); char *textfile_get(const char *pathname, const char *key); char *textfile_caseget(const char *pathname, const char *key); typedef void (*textfile_cb) (char *key, char *value, void *data); int textfile_foreach(const char *pathname, textfile_cb func, void *data); #endif /* __TEXTFILE_H */ bluez-4.101/src/bluetooth.conf0000644000000000000000000000214511766125764013213 00000000000000 bluez-4.101/src/manager.c0000644000000000000000000002440711766125764012122 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include "glib-helper.h" #include "hcid.h" #include "dbus-common.h" #include "log.h" #include "adapter.h" #include "error.h" #include "manager.h" static char base_path[50] = "/org/bluez"; static DBusConnection *connection = NULL; static int default_adapter_id = -1; static GSList *adapters = NULL; const char *manager_get_base_path(void) { return base_path; } static DBusMessage *default_adapter(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessage *reply; struct btd_adapter *adapter; const gchar *path; adapter = manager_find_adapter_by_id(default_adapter_id); if (!adapter) return btd_error_no_such_adapter(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; path = adapter_get_path(adapter); dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); return reply; } static DBusMessage *find_adapter(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessage *reply; struct btd_adapter *adapter; const char *pattern; int dev_id; const gchar *path; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern, DBUS_TYPE_INVALID)) return NULL; /* hci_devid() would make sense to use here, except it is * restricted to devices which are up */ if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) { path = adapter_any_get_path(); if (path != NULL) goto done; return btd_error_no_such_adapter(msg); } else if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4) { dev_id = atoi(pattern + 3); adapter = manager_find_adapter_by_id(dev_id); } else { bdaddr_t bdaddr; str2ba(pattern, &bdaddr); adapter = manager_find_adapter(&bdaddr); } if (!adapter) return btd_error_no_such_adapter(msg); path = adapter_get_path(adapter); done: reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); return reply; } static DBusMessage *list_adapters(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessageIter iter; DBusMessageIter array_iter; DBusMessage *reply; GSList *l; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter); for (l = adapters; l; l = l->next) { struct btd_adapter *adapter = l->data; const gchar *path = adapter_get_path(adapter); dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_OBJECT_PATH, &path); } dbus_message_iter_close_container(&iter, &array_iter); return reply; } static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessage *reply; DBusMessageIter iter; DBusMessageIter dict; GSList *list; char **array; int i; reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); array = g_new0(char *, g_slist_length(adapters) + 1); for (i = 0, list = adapters; list; list = list->next) { struct btd_adapter *adapter = list->data; array[i] = (char *) adapter_get_path(adapter); i++; } dict_append_array(&dict, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i); g_free(array); dbus_message_iter_close_container(&iter, &dict); return reply; } static const GDBusMethodTable manager_methods[] = { { GDBUS_METHOD("GetProperties", NULL, GDBUS_ARGS({ "properties", "a{sv}" }), get_properties) }, { GDBUS_METHOD("DefaultAdapter", NULL, GDBUS_ARGS({ "adapter", "o" }), default_adapter) }, { GDBUS_METHOD("FindAdapter", GDBUS_ARGS({ "pattern", "s" }), GDBUS_ARGS({ "adapter", "o" }), find_adapter) }, { GDBUS_ASYNC_METHOD("ListAdapters", NULL, GDBUS_ARGS({ "adapters", "ao" }), list_adapters) }, { } }; static const GDBusSignalTable manager_signals[] = { { GDBUS_SIGNAL("PropertyChanged", GDBUS_ARGS({ "name", "s" }, { "value", "v" })) }, { GDBUS_SIGNAL("AdapterAdded", GDBUS_ARGS({ "adapter", "o" })) }, { GDBUS_SIGNAL("AdapterRemoved", GDBUS_ARGS({ "adapter", "o" })) }, { GDBUS_SIGNAL("DefaultAdapterChanged", GDBUS_ARGS({ "adapter", "o" })) }, { } }; dbus_bool_t manager_init(DBusConnection *conn, const char *path) { connection = conn; snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid()); return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE, manager_methods, manager_signals, NULL, NULL, NULL); } static void manager_update_adapters(void) { GSList *list; char **array; int i; array = g_new0(char *, g_slist_length(adapters) + 1); for (i = 0, list = adapters; list; list = list->next) { struct btd_adapter *adapter = list->data; array[i] = (char *) adapter_get_path(adapter); i++; } emit_array_property_changed(connection, "/", MANAGER_INTERFACE, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i); g_free(array); } static void manager_set_default_adapter(int id) { struct btd_adapter *adapter; const gchar *path; default_adapter_id = id; adapter = manager_find_adapter_by_id(id); if (!adapter) return; path = adapter_get_path(adapter); g_dbus_emit_signal(connection, "/", MANAGER_INTERFACE, "DefaultAdapterChanged", DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); } struct btd_adapter *manager_get_default_adapter(void) { return manager_find_adapter_by_id(default_adapter_id); } static void manager_remove_adapter(struct btd_adapter *adapter) { uint16_t dev_id = adapter_get_dev_id(adapter); const gchar *path = adapter_get_path(adapter); adapters = g_slist_remove(adapters, adapter); manager_update_adapters(); if (default_adapter_id == dev_id || default_adapter_id < 0) { int new_default = hci_get_route(NULL); manager_set_default_adapter(new_default); } g_dbus_emit_signal(connection, "/", MANAGER_INTERFACE, "AdapterRemoved", DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); adapter_remove(adapter); btd_adapter_unref(adapter); if (adapters == NULL) btd_start_exit_timer(); } void manager_cleanup(DBusConnection *conn, const char *path) { while (adapters) { struct btd_adapter *adapter = adapters->data; adapters = g_slist_remove(adapters, adapter); adapter_remove(adapter); btd_adapter_unref(adapter); } btd_start_exit_timer(); g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE); } static gint adapter_id_cmp(gconstpointer a, gconstpointer b) { struct btd_adapter *adapter = (struct btd_adapter *) a; uint16_t id = GPOINTER_TO_UINT(b); uint16_t dev_id = adapter_get_dev_id(adapter); return dev_id == id ? 0 : -1; } static gint adapter_cmp(gconstpointer a, gconstpointer b) { struct btd_adapter *adapter = (struct btd_adapter *) a; const bdaddr_t *bdaddr = b; bdaddr_t src; adapter_get_address(adapter, &src); return bacmp(&src, bdaddr); } struct btd_adapter *manager_find_adapter(const bdaddr_t *sba) { GSList *match; match = g_slist_find_custom(adapters, sba, adapter_cmp); if (!match) return NULL; return match->data; } struct btd_adapter *manager_find_adapter_by_id(int id) { GSList *match; match = g_slist_find_custom(adapters, GINT_TO_POINTER(id), adapter_id_cmp); if (!match) return NULL; return match->data; } void manager_foreach_adapter(adapter_cb func, gpointer user_data) { g_slist_foreach(adapters, (GFunc) func, user_data); } GSList *manager_get_adapters(void) { return adapters; } void manager_add_adapter(const char *path) { g_dbus_emit_signal(connection, "/", MANAGER_INTERFACE, "AdapterAdded", DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); manager_update_adapters(); btd_stop_exit_timer(); } struct btd_adapter *btd_manager_register_adapter(int id, gboolean up) { struct btd_adapter *adapter; const char *path; adapter = manager_find_adapter_by_id(id); if (adapter) { error("Unable to register adapter: hci%d already exist", id); return NULL; } adapter = adapter_create(connection, id); if (!adapter) return NULL; adapters = g_slist_append(adapters, adapter); if (!adapter_init(adapter, up)) { adapters = g_slist_remove(adapters, adapter); btd_adapter_unref(adapter); return NULL; } path = adapter_get_path(adapter); g_dbus_emit_signal(connection, "/", MANAGER_INTERFACE, "AdapterAdded", DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID); manager_update_adapters(); btd_stop_exit_timer(); if (default_adapter_id < 0) manager_set_default_adapter(id); if (main_opts.did_source) btd_adapter_set_did(adapter, main_opts.did_vendor, main_opts.did_product, main_opts.did_version, main_opts.did_source); DBG("Adapter %s registered", path); return btd_adapter_ref(adapter); } int btd_manager_unregister_adapter(int id) { struct btd_adapter *adapter; const gchar *path; adapter = manager_find_adapter_by_id(id); if (!adapter) return -1; path = adapter_get_path(adapter); info("Unregister path: %s", path); manager_remove_adapter(adapter); return 0; } bluez-4.101/src/error.h0000644000000000000000000000345611571052274011634 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2007-2008 Fabien Chevalier * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include #define ERROR_INTERFACE "org.bluez.Error" DBusMessage *btd_error_invalid_args(DBusMessage *msg); DBusMessage *btd_error_busy(DBusMessage *msg); DBusMessage *btd_error_already_exists(DBusMessage *msg); DBusMessage *btd_error_not_supported(DBusMessage *msg); DBusMessage *btd_error_not_connected(DBusMessage *msg); DBusMessage *btd_error_already_connected(DBusMessage *msg); DBusMessage *btd_error_not_available(DBusMessage *msg); DBusMessage *btd_error_in_progress(DBusMessage *msg); DBusMessage *btd_error_does_not_exist(DBusMessage *msg); DBusMessage *btd_error_not_authorized(DBusMessage *msg); DBusMessage *btd_error_no_such_adapter(DBusMessage *msg); DBusMessage *btd_error_agent_not_available(DBusMessage *msg); DBusMessage *btd_error_not_ready(DBusMessage *msg); DBusMessage *btd_error_failed(DBusMessage *msg, const char *str); bluez-4.101/src/oob.c0000644000000000000000000000232711571052274011251 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 ST-Ericsson SA * * Author: Szymon Janc for ST-Ericsson * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #include "adapter.h" #include "oob.h" static oob_read_cb_t local_oob_read_cb = NULL; void oob_register_cb(oob_read_cb_t cb) { local_oob_read_cb = cb; } void oob_read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash, uint8_t *randomizer) { if (local_oob_read_cb) local_oob_read_cb(adapter, hash, randomizer); } bluez-4.101/src/agent.h0000644000000000000000000000536411766125764011614 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ struct agent; typedef void (*agent_cb) (struct agent *agent, DBusError *err, void *user_data); typedef void (*agent_pincode_cb) (struct agent *agent, DBusError *err, const char *pincode, void *user_data); typedef void (*agent_passkey_cb) (struct agent *agent, DBusError *err, uint32_t passkey, void *user_data); typedef void (*agent_remove_cb) (struct agent *agent, void *user_data); struct agent *agent_create(struct btd_adapter *adapter, const char *name, const char *path, uint8_t capability, agent_remove_cb cb, void *remove_cb_data); void agent_free(struct agent *agent); int agent_authorize(struct agent *agent, const char *path, const char *uuid, agent_cb cb, void *user_data, GDestroyNotify destroy); int agent_request_pincode(struct agent *agent, struct btd_device *device, agent_pincode_cb cb, gboolean secure, void *user_data, GDestroyNotify destroy); int agent_confirm_mode_change(struct agent *agent, const char *new_mode, agent_cb cb, void *user_data, GDestroyNotify destroy); int agent_request_passkey(struct agent *agent, struct btd_device *device, agent_passkey_cb cb, void *user_data, GDestroyNotify destroy); int agent_request_confirmation(struct agent *agent, struct btd_device *device, uint32_t passkey, agent_cb cb, void *user_data, GDestroyNotify destroy); int agent_display_passkey(struct agent *agent, struct btd_device *device, uint32_t passkey); int agent_display_pincode(struct agent *agent, struct btd_device *device, const char *pincode, agent_cb cb, void *user_data, GDestroyNotify destroy); int agent_cancel(struct agent *agent); gboolean agent_is_busy(struct agent *agent, void *user_data); uint8_t agent_get_io_capability(struct agent *agent); gboolean agent_matches(struct agent *agent, const char *name, const char *path); void agent_init(void); void agent_exit(void); bluez-4.101/src/attrib-server.h0000644000000000000000000000330611766125764013301 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2010 Nokia Corporation * Copyright (C) 2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid, uint16_t nitems); struct attribute *attrib_db_add(struct btd_adapter *adapter, uint16_t handle, bt_uuid_t *uuid, int read_reqs, int write_reqs, const uint8_t *value, int len); int attrib_db_update(struct btd_adapter *adapter, uint16_t handle, bt_uuid_t *uuid, const uint8_t *value, int len, struct attribute **attr); int attrib_db_del(struct btd_adapter *adapter, uint16_t handle); int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid, const uint8_t *value, int len); uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle, const char *name); void attrib_free_sdp(uint32_t sdp_handle); guint attrib_channel_attach(GAttrib *attrib); gboolean attrib_channel_detach(GAttrib *attrib, guint id); bluez-4.101/src/sdp-xml.h0000644000000000000000000000403111571052274012055 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2005-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __SDP_XML_H #define __SDP_XML_H #include #define SDP_XML_ENCODING_NORMAL 0 #define SDP_XML_ENCODING_HEX 1 void convert_sdp_record_to_xml(sdp_record_t *rec, void *user_data, void (*append_func) (void *, const char *)); sdp_data_t *sdp_xml_parse_nil(const char *data); sdp_data_t *sdp_xml_parse_text(const char *data, char encoding); sdp_data_t *sdp_xml_parse_url(const char *data); sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd); sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record); struct sdp_xml_data { char *text; /* Pointer to the current buffer */ int size; /* Size of the current buffer */ sdp_data_t *data; /* The current item being built */ struct sdp_xml_data *next; /* Next item on the stack */ char type; /* 0 = Text or Hexadecimal */ char *name; /* Name, optional in the dtd */ /* TODO: What is it used for? */ }; struct sdp_xml_data *sdp_xml_data_alloc(void); void sdp_xml_data_free(struct sdp_xml_data *elem); struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem); sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem, sdp_record_t *record); #endif /* __SDP_XML_H */ bluez-4.101/src/event.h0000644000000000000000000000473311766125764011636 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, gboolean secure); void btd_event_device_found(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, int8_t rssi, uint8_t confirm_name, uint8_t *data, uint8_t data_len); void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer, gboolean legacy); void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class); void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name); void btd_event_conn_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, char *name, uint8_t *dev_class); void btd_event_conn_failed(bdaddr_t *local, bdaddr_t *peer, uint8_t status); void btd_event_disconn_complete(bdaddr_t *local, bdaddr_t *peer); void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer, uint8_t status); void btd_event_returned_link_key(bdaddr_t *local, bdaddr_t *peer); int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey); int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba); int btd_event_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey); void btd_event_device_blocked(bdaddr_t *local, bdaddr_t *peer); void btd_event_device_unblocked(bdaddr_t *local, bdaddr_t *peer); void btd_event_device_unpaired(bdaddr_t *local, bdaddr_t *peer); int btd_event_link_key_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t *key, uint8_t key_type, uint8_t pin_length); int btd_event_ltk_notify(bdaddr_t *local, bdaddr_t *peer, uint8_t bdaddr_type, uint8_t *key, uint8_t master, uint8_t authenticated, uint8_t enc_size, uint16_t ediv, uint8_t rand[8]); bluez-4.101/src/eir.c0000644000000000000000000002075311766125764011267 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2011 Nokia Corporation * Copyright (C) 2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include "glib-helper.h" #include "eir.h" void eir_data_free(struct eir_data *eir) { g_slist_free_full(eir->services, g_free); eir->services = NULL; g_free(eir->name); eir->name = NULL; } static void eir_parse_uuid16(struct eir_data *eir, void *data, uint8_t len) { uint16_t *uuid16 = data; uuid_t service; char *uuid_str; unsigned int i; service.type = SDP_UUID16; for (i = 0; i < len / 2; i++, uuid16++) { service.value.uuid16 = btohs(bt_get_unaligned(uuid16)); uuid_str = bt_uuid2string(&service); eir->services = g_slist_append(eir->services, uuid_str); } } static void eir_parse_uuid32(struct eir_data *eir, void *data, uint8_t len) { uint32_t *uuid32 = data; uuid_t service; char *uuid_str; unsigned int i; service.type = SDP_UUID32; for (i = 0; i < len / 4; i++, uuid32++) { service.value.uuid32 = btohl(bt_get_unaligned(uuid32)); uuid_str = bt_uuid2string(&service); eir->services = g_slist_append(eir->services, uuid_str); } } static void eir_parse_uuid128(struct eir_data *eir, uint8_t *data, uint8_t len) { uint8_t *uuid_ptr = data; uuid_t service; char *uuid_str; unsigned int i; int k; service.type = SDP_UUID128; for (i = 0; i < len / 16; i++) { for (k = 0; k < 16; k++) service.value.uuid128.data[k] = uuid_ptr[16 - k - 1]; uuid_str = bt_uuid2string(&service); eir->services = g_slist_append(eir->services, uuid_str); uuid_ptr += 16; } } int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len) { uint16_t len = 0; eir->flags = -1; /* No EIR data to parse */ if (eir_data == NULL) return 0; while (len < eir_len - 1) { uint8_t field_len = eir_data[0]; uint8_t data_len, *data = &eir_data[2]; /* Check for the end of EIR */ if (field_len == 0) break; len += field_len + 1; /* Do not continue EIR Data parsing if got incorrect length */ if (len > eir_len) break; data_len = field_len - 1; switch (eir_data[1]) { case EIR_UUID16_SOME: case EIR_UUID16_ALL: eir_parse_uuid16(eir, data, data_len); break; case EIR_UUID32_SOME: case EIR_UUID32_ALL: eir_parse_uuid32(eir, data, data_len); break; case EIR_UUID128_SOME: case EIR_UUID128_ALL: eir_parse_uuid128(eir, data, data_len); break; case EIR_FLAGS: if (data_len > 0) eir->flags = *data; break; case EIR_NAME_SHORT: case EIR_NAME_COMPLETE: /* Some vendors put a NUL byte terminator into * the name */ while (data_len > 0 && data[data_len - 1] == '\0') data_len--; if (!g_utf8_validate((char *) data, data_len, NULL)) break; g_free(eir->name); eir->name = g_strndup((char *) data, data_len); eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE; break; case EIR_CLASS_OF_DEV: if (data_len < 3) break; memcpy(eir->dev_class, data, 3); break; case EIR_GAP_APPEARANCE: if (data_len < 2) break; eir->appearance = bt_get_le16(data); break; } eir_data += field_len + 1; } return 0; } #define SIZEOF_UUID128 16 static void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_t *eir_len) { int i, k, uuid_count = 0; uint16_t len = *eir_len; uint8_t *uuid128; gboolean truncated = FALSE; /* Store UUIDs in place, skip 2 bytes to write type and length later */ uuid128 = ptr + 2; for (; list; list = list->next) { struct uuid_info *uuid = list->data; uint8_t *uuid128_data = uuid->uuid.value.uuid128.data; if (uuid->uuid.type != SDP_UUID128) continue; /* Stop if not enough space to put next UUID128 */ if ((len + 2 + SIZEOF_UUID128) > HCI_MAX_EIR_LENGTH) { truncated = TRUE; break; } /* Check for duplicates, EIR data is Little Endian */ for (i = 0; i < uuid_count; i++) { for (k = 0; k < SIZEOF_UUID128; k++) { if (uuid128[i * SIZEOF_UUID128 + k] != uuid128_data[SIZEOF_UUID128 - 1 - k]) break; } if (k == SIZEOF_UUID128) break; } if (i < uuid_count) continue; /* EIR data is Little Endian */ for (k = 0; k < SIZEOF_UUID128; k++) uuid128[uuid_count * SIZEOF_UUID128 + k] = uuid128_data[SIZEOF_UUID128 - 1 - k]; len += SIZEOF_UUID128; uuid_count++; } if (uuid_count > 0 || truncated) { /* EIR Data length */ ptr[0] = (uuid_count * SIZEOF_UUID128) + 1; /* EIR Data type */ ptr[1] = truncated ? EIR_UUID128_SOME : EIR_UUID128_ALL; len += 2; *eir_len = len; } } void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor, uint16_t did_product, uint16_t did_version, uint16_t did_source, GSList *uuids, uint8_t *data) { GSList *l; uint8_t *ptr = data; uint16_t eir_len = 0; uint16_t uuid16[HCI_MAX_EIR_LENGTH / 2]; int i, uuid_count = 0; gboolean truncated = FALSE; size_t name_len; name_len = strlen(name); if (name_len > 0) { /* EIR Data type */ if (name_len > 48) { name_len = 48; ptr[1] = EIR_NAME_SHORT; } else ptr[1] = EIR_NAME_COMPLETE; /* EIR Data length */ ptr[0] = name_len + 1; memcpy(ptr + 2, name, name_len); eir_len += (name_len + 2); ptr += (name_len + 2); } if (tx_power != 0) { *ptr++ = 2; *ptr++ = EIR_TX_POWER; *ptr++ = (uint8_t) tx_power; eir_len += 3; } if (did_vendor != 0x0000) { *ptr++ = 9; *ptr++ = EIR_DEVICE_ID; *ptr++ = (did_source & 0x00ff); *ptr++ = (did_source & 0xff00) >> 8; *ptr++ = (did_vendor & 0x00ff); *ptr++ = (did_vendor & 0xff00) >> 8; *ptr++ = (did_product & 0x00ff); *ptr++ = (did_product & 0xff00) >> 8; *ptr++ = (did_version & 0x00ff); *ptr++ = (did_version & 0xff00) >> 8; eir_len += 10; } /* Group all UUID16 types */ for (l = uuids; l != NULL; l = g_slist_next(l)) { struct uuid_info *uuid = l->data; if (uuid->uuid.type != SDP_UUID16) continue; if (uuid->uuid.value.uuid16 < 0x1100) continue; if (uuid->uuid.value.uuid16 == PNP_INFO_SVCLASS_ID) continue; /* Stop if not enough space to put next UUID16 */ if ((eir_len + 2 + sizeof(uint16_t)) > HCI_MAX_EIR_LENGTH) { truncated = TRUE; break; } /* Check for duplicates */ for (i = 0; i < uuid_count; i++) if (uuid16[i] == uuid->uuid.value.uuid16) break; if (i < uuid_count) continue; uuid16[uuid_count++] = uuid->uuid.value.uuid16; eir_len += sizeof(uint16_t); } if (uuid_count > 0) { /* EIR Data length */ ptr[0] = (uuid_count * sizeof(uint16_t)) + 1; /* EIR Data type */ ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; ptr += 2; eir_len += 2; for (i = 0; i < uuid_count; i++) { *ptr++ = (uuid16[i] & 0x00ff); *ptr++ = (uuid16[i] & 0xff00) >> 8; } } /* Group all UUID128 types */ if (eir_len <= HCI_MAX_EIR_LENGTH - 2) eir_generate_uuid128(uuids, ptr, &eir_len); } gboolean eir_has_data_type(uint8_t *data, size_t len, uint8_t type) { uint8_t field_len; size_t parsed = 0; while (parsed < len - 1) { field_len = data[0]; if (field_len == 0) break; parsed += field_len + 1; if (parsed > len) break; if (data[1] == type) return TRUE; data += field_len + 1; } return FALSE; } size_t eir_append_data(uint8_t *eir, size_t eir_len, uint8_t type, uint8_t *data, size_t data_len) { eir[eir_len++] = sizeof(type) + data_len; eir[eir_len++] = type; memcpy(&eir[eir_len], data, data_len); eir_len += data_len; return eir_len; } size_t eir_length(uint8_t *eir, size_t maxlen) { uint8_t field_len; size_t parsed = 0, length = 0; while (parsed < maxlen - 1) { field_len = eir[0]; if (field_len == 0) break; parsed += field_len + 1; if (parsed > maxlen) break; length = parsed; eir += field_len + 1; } return length; } bluez-4.101/src/error.c0000644000000000000000000000626511571052274011630 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2006-2010 Nokia Corporation * Copyright (C) 2004-2010 Marcel Holtmann * Copyright (C) 2007-2008 Fabien Chevalier * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include "error.h" DBusMessage *btd_error_invalid_args(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".InvalidArguments", "Invalid arguments in method call"); } DBusMessage *btd_error_busy(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", "Operation already in progress"); } DBusMessage *btd_error_already_exists(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyExists", "Already Exists"); } DBusMessage *btd_error_not_supported(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".NotSupported", "Operation is not supported"); } DBusMessage *btd_error_not_connected(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".NotConnected", "Not Connected"); } DBusMessage *btd_error_already_connected(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".AlreadyConnected", "Already Connected"); } DBusMessage *btd_error_in_progress(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".InProgress", "In Progress"); } DBusMessage *btd_error_not_available(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAvailable", "Operation currently not available"); } DBusMessage *btd_error_does_not_exist(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".DoesNotExist", "Does Not Exist"); } DBusMessage *btd_error_not_authorized(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".NotAuthorized", "Operation Not Authorized"); } DBusMessage *btd_error_no_such_adapter(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".NoSuchAdapter", "No such adapter"); } DBusMessage *btd_error_agent_not_available(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".AgentNotAvailable", "Agent Not Available"); } DBusMessage *btd_error_not_ready(DBusMessage *msg) { return g_dbus_create_error(msg, ERROR_INTERFACE ".NotReady", "Resource Not Ready"); } DBusMessage *btd_error_failed(DBusMessage *msg, const char *str) { return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "%s", str); } bluez-4.101/src/genbuiltin0000755000000000000000000000040011272762165012407 00000000000000#!/bin/sh for i in $* do echo "extern struct bluetooth_plugin_desc __bluetooth_builtin_$i;" done echo echo "static struct bluetooth_plugin_desc *__bluetooth_builtin[] = {" for i in $* do echo " &__bluetooth_builtin_$i," done echo " NULL" echo "};" bluez-4.101/src/glib-helper.h0000644000000000000000000000206211766125764012700 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ gchar *bt_uuid2string(uuid_t *uuid); char *bt_name2string(const char *string); int bt_string2uuid(uuid_t *uuid, const char *string); gchar *bt_list2string(GSList *list); GSList *bt_string2list(const gchar *str); bluez-4.101/src/log.c0000644000000000000000000000531511766125764011266 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2004-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "log.h" void info(const char *format, ...) { va_list ap; va_start(ap, format); vsyslog(LOG_INFO, format, ap); va_end(ap); } void warn(const char *format, ...) { va_list ap; va_start(ap, format); vsyslog(LOG_WARNING, format, ap); va_end(ap); } void error(const char *format, ...) { va_list ap; va_start(ap, format); vsyslog(LOG_ERR, format, ap); va_end(ap); } void btd_debug(const char *format, ...) { va_list ap; va_start(ap, format); vsyslog(LOG_DEBUG, format, ap); va_end(ap); } extern struct btd_debug_desc __start___debug[]; extern struct btd_debug_desc __stop___debug[]; static gchar **enabled = NULL; static gboolean is_enabled(struct btd_debug_desc *desc) { int i; if (enabled == NULL) return 0; for (i = 0; enabled[i] != NULL; i++) if (desc->file != NULL && g_pattern_match_simple(enabled[i], desc->file) == TRUE) return 1; return 0; } void __btd_enable_debug(struct btd_debug_desc *start, struct btd_debug_desc *stop) { struct btd_debug_desc *desc; if (start == NULL || stop == NULL) return; for (desc = start; desc < stop; desc++) { if (is_enabled(desc)) desc->flags |= BTD_DEBUG_FLAG_PRINT; } } void __btd_toggle_debug(void) { struct btd_debug_desc *desc; for (desc = __start___debug; desc < __stop___debug; desc++) desc->flags |= BTD_DEBUG_FLAG_PRINT; } void __btd_log_init(const char *debug, int detach) { int option = LOG_NDELAY | LOG_PID; if (debug != NULL) enabled = g_strsplit_set(debug, ":, ", 0); __btd_enable_debug(__start___debug, __stop___debug); if (!detach) option |= LOG_PERROR; openlog("bluetoothd", option, LOG_DAEMON); syslog(LOG_INFO, "Bluetooth daemon %s", VERSION); } void __btd_log_cleanup(void) { closelog(); g_strfreev(enabled); } bluez-4.101/config.guess0000755000000000000000000012743211771117505012065 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, # 2011, 2012 Free Software Foundation, Inc. timestamp='2012-02-10' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program 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 # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Per Bothner. Please send patches (context # diff format) to and include a ChangeLog # entry. # # This script attempts to guess a canonical system name similar to # config.sub. If it succeeds, it prints the system name on stdout, and # exits with 0. Otherwise, it exits with 1. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-gnu else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-gnueabi else echo ${UNAME_MACHINE}-unknown-linux-gnueabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-gnu exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:Linux:*:*) LIBC=gnu eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; padre:Linux:*:*) echo sparc-unknown-linux-gnu exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in i386) eval $set_cc_for_build if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then UNAME_PROCESSOR="x86_64" fi fi ;; unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build cat >$dummy.c < # include #endif main () { #if defined (sony) #if defined (MIPSEB) /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, I don't know.... */ printf ("mips-sony-bsd\n"); exit (0); #else #include printf ("m68k-sony-newsos%s\n", #ifdef NEWSOS4 "4" #else "" #endif ); exit (0); #endif #endif #if defined (__arm) && defined (__acorn) && defined (__unix) printf ("arm-acorn-riscix\n"); exit (0); #endif #if defined (hp300) && !defined (hpux) printf ("m68k-hp-bsd\n"); exit (0); #endif #if defined (NeXT) #if !defined (__ARCHITECTURE__) #define __ARCHITECTURE__ "m68k" #endif int version; version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); exit (0); #endif #if defined (MULTIMAX) || defined (n16) #if defined (UMAXV) printf ("ns32k-encore-sysv\n"); exit (0); #else #if defined (CMU) printf ("ns32k-encore-mach\n"); exit (0); #else printf ("ns32k-encore-bsd\n"); exit (0); #endif #endif #endif #if defined (__386BSD__) printf ("i386-pc-bsd\n"); exit (0); #endif #if defined (sequent) #if defined (i386) printf ("i386-sequent-dynix\n"); exit (0); #endif #if defined (ns32000) printf ("ns32k-sequent-dynix\n"); exit (0); #endif #endif #if defined (_SEQUENT_) struct utsname un; uname(&un); if (strncmp(un.version, "V2", 2) == 0) { printf ("i386-sequent-ptx2\n"); exit (0); } if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ printf ("i386-sequent-ptx1\n"); exit (0); } printf ("i386-sequent-ptx\n"); exit (0); #endif #if defined (vax) # if !defined (ultrix) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # else printf ("vax-dec-ultrix\n"); exit (0); # endif #endif #if defined (alliant) && defined (i860) printf ("i860-alliant-bsd\n"); exit (0); #endif exit (1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # Convex versions that predate uname can use getsysinfo(1) if [ -x /usr/convex/getsysinfo ] then case `getsysinfo -f cpu_type` in c1*) echo c1-convex-bsd exit ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: bluez-4.101/ChangeLog0000644000000000000000000017771211771117441011324 00000000000000ver 4.101: Fix issue with missing BlueZ service file. Fix issue with aborting A2DP setup during AVDTP start. Fix issue with handling of multiple A2DP indication. Fix issue with handling AVDTP abort with invalid SEID. Fix issue with rejecting AVDTP abort commands. Add support for handling AVDTP command collision. ver 4.100: Fix issue with crashing when SCO connection fails. Fix issue with HFP gateway failing on first GSM connection. Fix issue with AVRCP and handling of vendor commands. Fix issue with handling AVRCP subunit info command. Fix issue with missing capability for AVRCP track reached end. Fix issue with AVDTP signaling and GStreamer SBC NULL check. Fix issue with AVDTP Reconfigure Reject message. Fix issue with incorrect EIR length parsing. Fix issue with SDP disconnect for HIDSDPDisable. Fix issue with SDP interoperability with Mac OS X Lion. Fix issue with reverse SDP discovery with some devices. Fix issue with discovering state during power off operation. Add support for AVRCP Volume Changed notifications. Add support for AVRCP Set Absolute Volume handling. Add support for display legacy PIN code agent method. Add support for multiple media transports per endpoint. Add support for discovering device information characteristics. Add support for vendor source for Device ID setting. Add support for immediate alert server. Add support for link loss server. Notes: This version requires D-Bus 1.4 or later. This version requires GLib 2.28 or later. ver 4.99: Fix issue with missing retries for BNEP connection setup. Fix issue with not showing name if first EIR has no details. Fix issue with running SDP discovery for LE devices. Add support for GATT using 128-bit Bluetooth UUIDs. Add support for retrieving key size information. Add support for storing Long Term Keys. Add support for Proximity Reporter API. Add support for KeyboardDisplay IO capability. Add support for version 1.0 of management API. Add support for monitoring interface. ver 4.98: Fix issue with adapter list upon initialization failure. Fix issue with missing legacy property for Low Energy. Fix issue with missing EIR information handling. Fix issue with device address type tracking. Fix issue with alert level characteristic. Fix issue with headset shutdown handling. Fix issue with Wiimote address handling. Add support for advanced l2test options. Add support for attribute protocol and multiple adapters. ver 4.97: Update support for proximity profile. Fix issue with SBC audio decoding quality. Fix multiple issues with HFP support. Fix multiple issues with A2DP support. Fix multiple issues with AVDTP support. Fix multiple issues with AVRCP support. Add support for AVRCP meta-data transfer. Add support for Bluetooth based thermometers. ver 4.96: Fix issue with race condition in AVDTP stream start. Fix issue with global adapter offline switching. Fix issue with pairing and No Bonding devices. Add support for Nintendo Wii Remote pairing. ver 4.95: Fix issue with AVCTP replies with invalid PID. Fix issue with AVRCP and unknown packet types. Fix issue with AVRCP not using NOT_IMPLEMENTED correctly. Fix issue with AVDTP discovery if all endpoints are in use. Fix issue with invalid memory writes and media support. Fix issue with not removing device alias and unbonding. Fix issue with device disconnects and offline mode handling. Add support for setting adapter name based on machine-info. Add support for systemd service configuration. ver 4.94: Fix issue with invalid read of memory in various modules. Fix issue with buffer overflow when sending AVDTP commands. Fix issue with response to vendor dependent AVRCP commands. Fix issue with headset when not able to reply with ERROR. Fix issue with crash when creating a device from storage. Fix issue with handling non UTF-8 devices names. Add support for improved discovery procedure. ver 4.93: Fix issue with property type and Health Main channel. Fix issue with crash when removing devices. Add support for hid2hci and udev integration. ver 4.92: Fix issue with handling of A2DP suspend response. Fix issue with crashing when acquiring A2DP stream. Fix issue with missing check for valid SCO before shutdown. Fix issue with waiting for POLLERR when disconnecting SCO. Fix issue with disconnect after primary service discovery. Fix issue with attribute interface registration. Add support for primary services over BR/EDR. Add support for flushable packets of A2DP media. ver 4.91: Fix issue with LMP version string and hciconfig. Fix issue with missing discovery signal when scanning. Fix issue with wrong state and canceling name resolving. Fix issue with missing check during adapter initialization. Fix issue with missing protocol not supported error and A2DP. Fix issue with crash during driver unregistering and A2DP. Fix issue with crash when receiving AVDTP close command. Fix issue with remote SEP handling when A2DP codec changes. Fix issue with SCO hangup handling and state changes. Fix issue with security level and MCAP instances. Fix issue with memory leak and HDP data channels. Add support for discover characteristics by UUID to gatttool. Add initial support for Out-of-Band association model. Add initial support for SIM Access Profile. ver 4.90: Fix issue with setting of global mode property. Fix issue with handling of RequestSession responses. Fix issue with TP_BNEP_CTRL_BV_01_C qualification test. Fix issue with too short AVDTP request timeout. Add support for SIM Access Profile manager. Add support for new UUID utility functions. Add support for attribute server notifications. Add support for client characteristic configuration. Update support for interactive GATT utility. ver 4.89: Fix issue with name resolving when discovery is suspended. Fix issue with parsing flags of advertising report. Fix issue with SEP handling if interface is disabled. Fix issue with device object creation on disconnect event. Fix issue with indicators whenever the driver is initialized. Fix issue with call indicator when parsing call info reply. Fix issue with crash and allowed GATT MTU was too large. Add support for SDP record of Primary GATT services. Add support for interactive mode for GATT utility. ver 4.88: Fix issue with HID channel reference count handling. Fix issue with daemon exit on badly formatted AT+VTS. Fix issue with crash while parsing of endpoint properties. Fix issue with possible crash on AVDTP Suspend request timeout. Fix issue with stopping inquiry before adapter is initialized. Fix issue with creating device object when connection fails. Fix issue with sending HCIDEVUP when adapter is already up. Fix issue with handling bonding IO channel closing. Fix agent cancellation in security mode 3 situations. Update pairing code to support management interface. ver 4.87: Fix issue with initialization when adapter is already up. Fix issue with attribute server MTU and incoming connections. Fix issue with duplicate characteristics after discovery. ver 4.86: Revert wrong fix for SDP PDU size error response. Fix various memory leaks in A2DP and AVDTP support. Add Routing property to MediaTransport interface Add proper tracking mechanism to NREC status. Add READ_BLOB_REQUEST support to attribute server. ver 4.85: Fix issue with event mask setting for older adapters. Fix issue with device creation and pairing failures. Add support for telephony support via oFono. Add support for characteristic security level. Update support for service registration. ver 4.84: Fix issue with wrong parameters and device found signals. Fix issue with leaking EIR data if RSSI does not change. Fix issue with adapter initialization state. Fix issue with closing of SDP server sockets. ver 4.83: Fix issue with already connected HFP/HSP endpoints. Fix missing reply when create device is canceled. Fix memory leak within the attribute server. Fix memory leak with unused extended inquiry name. Fix setting paired state when device->authr is false. Fix clearing authentication request for renewed keys. Add support for storing link keys in runtime memory. Update support for primary service discovery. ver 4.82: Fix crash with mmap of files with multiples of page size. Fix HFP response and hold (AT+BTRH) command response. Fix device creation error response when powered off. Fix device removal when connecting/browsing fails. Add initial attribute permission implementation. Add AVDTP SRC stream send buffer size verification. Add support for setting link policy based on features. ver 4.81: Fix issue with telephony driver initialization. Fix issue with adapter services list initialization. Fix crash after simultaneous authentication requests. Add support for primary service search on device creation. ver 4.80: Fix legacy link key storing for some buggy adapters. Fix invalid memory access when EIR field length is zero. Fix adapter initialization to wait for kernel HCI commands. Fix initialization of adapters which are already up. Fix possible race condition when initializing adapters. Fix possible crashes when attempting to connect AVDTP. Fix not aborting sink stream configuration on disconnect. Fix not indicating disconnected state when connecting to AVDTP. Fix not dropping AVDTP session when canceling stream setup. Fix AVDTP abort not being send when the state is idle. Fix regression with Low Energy and interleave discovery. Add a new configuration option to disable Low Energy support. Add iwmmxt optimization for SBC for ARM PXA series CPUs. Update support for GATT Primary Service Discovery. Update MCAP and HDP support. ver 4.79: Fix issue with adapter initialization race condition. Update new Bluetooth Management interface support. ver 4.78: Fix various issues with AVDTP timer handling. Fix various issues with handling of mode changes. Fix issue with audio disconnect watch in connecting state. Fix issue with handling call waiting indicators in telephony. Fix issue with handling UUID parameter and RegisterEndpoint. Add initial support for Bluetooth Management interface. Add support for Application property to HealthChannel. ver 4.77: Fix issue with device name and accessing already freed memory. Fix issue with handling CHLD=0 command for handsfree. Fix issue with manager properties and no adapters. Fix issue with properties and broken service records. Fix issue with A2DP playback and sample rate changes. Update MCAP and HDP support. ver 4.76: Fix issue in telephony driver with hanging up held call. Fix issue in telephony driver with notifications when on hold. Fix issue with blocking on setconf confirmation callback. Fix issue with not always signaling new streams as sinks. Fix issue with errors in case of endpoint request timeout. Fix issue with HFP/HSP microphone and speaker gain values. Add source if the device attempt to configure local sink stream. Add PSM option for GATT/ATT over BR/EDR on gatttool. Add support for GATT/ATT Attribute Write Request. Update MCAP and HDP support. ver 4.75: Fix use of uninitialized variable on legacy pairing. Fix mismatch of attribute protocol opcode. ver 4.74: Fix regression for Legacy Pairing. Fix wrong PSM value for attribute protocol. Fix issue with RSSI field in advertising reports. Add support for Add BR/EDR and LE interleaved discovery. Add support for GATT write characteristic value option. Add support for specifying download address for AR300x. ver 4.73: Fix problem with EIR data when setting the name. Fix reading local name from command complete event. Fix registering local endpoints with disabled socket interface. Add support for more HCI operations using ops infrastructure. Add support for GATT characteristic hierarchy. Add support for GATT indications. ver 4.72: Fix memory leak while connecting BTIO channels. Fix crash with GStreamer plugin if SBC is not supported. Fix issue with GATT server stop sending notifications. Fix issue with GATT and dealing with the minimum MTU size. Fix issue with file descriptor leak in GATT client. Add support for UUID 128-bit handling in attribute client. Add support for encoders/decoders for MTU Exchange. Add support for the MTU Exchange procedure to the server. Add support for a per channel MTU to the ATT server. Add support for Characteristic interface. Add support for new Media API and framework. Add initial support for HDP plugin. ver 4.71: Fix compilation when SBC support in not enabled. Fix crash with RequestSession and application disconnects. Fix memory leak and possible crash when removing audio device. Fix issue with closing stream of locked sep when reconfiguring. Fix issue where discovery could interfere with bonding. Fix issue with Connected status when PS3 BD remote connects. Fix issue with lifetime of fake input devices. Add support for compile time option of oui.txt path. Add support for printing IEEE1284 device ID for CUPS. Add plugin for setting adapter class via DMI. Add more features for attribute protocol and profile. Add initial support for MCAP. ver 4.70: Fix incoming call indication handling when in WAITING state. Fix various SDP related qualification test case issues. Fix logic to write EIR when SDP records are changed. Fix UTF-8 validity check for remote names in EIR. Add support for UUID-128 extended inquiry response. Add service UUIDs from EIR to the DeviceFound signal. Add fast connectable feature for Handsfree profile. Add HCI command and event definitions for AMP support. Add firmware download support for Qualcommh devices. Add host level support for Atheros AR300x device. Add initial support of ATT and GATT for basic rate. ver 4.69: Fix issue with calling g_option_context_free() twice. Fix inconsistencies with initial LE commands and events. Add support for telephony ClearLastNumber method. Add support for network server interface. ver 4.68: Fix initialization of adapters in RAW mode. Fix signal strength for HFP in Maemo's telephony support. Add support for following the radio state via Maemo's MCE. Add initial set of LE commands and events definitions. Add mode option for L2CAP sockets to the BtIO API. ver 4.67: Fix issue with authentication reply when bonding already completed. Fix issue with not canceling authentication when bonding fails. Fix issue with changed combination keys and temporary storage. Fix issue with sdp_get_supp_feat library function. Fix issue with missing unblock on device removal. Fix issue with not waiting for mode change completion. Add ARMv6 optimized version of analysis filter for SBC encoder. ver 4.66: Fix regression with full debug enabling via SIGUSR2. Fix redundant speaker/microphone gains being sent. Fix not emitting PropertyChanged for SpeakerGain/MicrophoneGain. Fix issue with storage usage when a record is not found in memory. Fix issue with DiscoverServices not retrieving any records. Fix audio profile disconnection order to match whitepaper. Fix auto-accept confirmation when local agent has NoInputNoOutput. Fix remote just-works SSP when MITM protection is required. Fix performing dedicated bonding without MITM requirement. Add support for storing debug link keys in runtime memory. ver 4.65: Fix issues with general bonding being default setting now. Fix driver removal upon device removal. Add new "Blocked" property to device objects. Add hciconfig support for blacklisting. Add support for dynamic debug feature. ver 4.64: Fix invalid memory access in headset_get_nrec function. Fix issue with disconnect event on higher protocol layers. Fix issue with list parsing in sdp_set_supp_features function. Fix device object reference counting for SDP browse requests. Add missing memory checks whenever memory is allocated for SDP. Add support for exporting local services via D-Bus. Add more L2CAP Enhanced Retransmission test options. ver 4.63: Fix avdtp_abort not canceling pending requests. Fix stale connection when abort gets rejected. ver 4.62: Fix accidental symbol breakage with inquiry transmit power. Fix using invalid data from previous headset connection. Fix double free on AVDTP Abort response. Fix possible crash while verifying AVDTP version. Fix missing inuse flag when AVDTP stream is configured. Add support for Bluetooth controller types. ver 4.61: Fix issues with Read Inquiry Response Transmit Power Level. Fix possible invalid read when removing a temporary device. Fix mode restoration when remember_powered is false. Fix conference call releasing in telephony-maemo. Fix segmentation fault with authorization during headset disconnects. Add support for handling unanswered AVDTP request on disconnect. Add support for handling Inquiry Response Transmit Power Level. Add support for caching of remote host features. Add preliminary voice dialing support for HSP. ver 4.60: Fix voice mailbox number reading from SIM. Fix some races with D-Bus mainloop integration. Add helpers for D-Bus signal watches. ver 4.59: Add values for Bluetooth 4.0 specification. Add SDP functions for HDP support. Add test scripts for input and audio. Fix missing close on BtIO create_io function. Fix sending incorrect AVDTP commands after timeout occurs. Fix timer removal when device disconnects unexpectedly. Fix Extended Inquiry Response record for Device ID. ver 4.58: Fix crash when adapter agent exists during authentication. Fix CK-20W quirks for play and pause events. ver 4.57: Fix unloading of drivers for uninitialized adapters. Fix debug message to use requested and not opened SEID. Fix codec selection for GStreamer plugin. Fix deleting of SDP records during service updates. Fix deleting of SDP records when a device is removed. Fix handling when the SDP record is modified on remote device. Fix potential buffer overflow by using snprintf instead of sprintf. Fix const declarations for some storage function parameters. ver 4.56: Add missing values from Bluetooth 3.0 specification. Add proper tracking of device paired status. Fix tracking of devices without permanently stored link key. Fix issue with link key removal after connection failures. Fix legacy pairing information based on remote host features. Fix off-by-one issue with AVDTP capability parsing. Fix AVRCP, AVCTP, AVDTP, A2DP and HFP version numbers. Fix agent canceling before calling agent_destroy. Fix service record parsing with an empty UUID list. Fix various SDP related memory leaks. ver 4.55: Add support for POSIX capabilities dropping. Add special quirk for the Nokia CK-20W car kit. Fix error code handling for AVDTP SetConfiguration response. Fix updating out of range list when RSSI hasn't changed. Fix various memory leaks and unnecessary error checks. ver 4.54: Add introspection interface to output of introspection calls. Fix stream handling when media transport disconnects prematurely. Fix command timeout handling when there's no stream. Fix headset_suspend_stream behavior for invalid states Fix issue with AVDTP ABORTING state transition. Fix issue with AVDTP suspend while closing. ver 4.53: Fix issue with telephony connection state notifications. Fix AVDTP stream leak for invalid media transport config. Fix audio connection authorization handling with timeouts. Fix race condition in authorizing audio connections. Fix device authorized setting for AVRCP-only connections. Fix duplicate attempts from device to connect signal channel. ver 4.52: Add AVCTP support to test utility. Fix AVDTP Abort when transport closes before response. Fix authorization when the audio profiles are slow to connect. Fix potential AVDTP reference leaks. ver 4.51: Add utility for basic AVDTP testing. Add support for configuring L2CAP FCS option. Fix discovery mode for CUPS 1.4.x and later. Fix global state tracking of audio service. Fix last issues with the new build system. ver 4.50: Fix issue with missing manual pages in distribution. Fix issue with the configuration and state directories. Fix issue with creating include directory. Fix dependencies of include file generation. ver 4.49: Add simple test program for basic GAP testing. Add support for confirmation requests to agent example. Add support for full non-recursive build. Add five millisecond delay for Simple Pairing auto-accept. Fix Class of Device setting when InitiallyPowered=false. ver 4.48: Add library function for comparing UUID values. Add support for creating all plugins as builtins. Add support for async handling of service class changes. Add support for source interface to audio IPC. Fix device name settings when device is off or down. Fix issue with enabled SCO server when not necessary. Fix missing D-Bus access policy for CUPS backend. Fix discovery results of CUPS backend. Fix initialization handling of Maemo telephony. ver 4.47: Add support for RFKILL unblock handling. Add support for serial proxy configurations. Add support for caching service class updates. Fix issues with updating SDP service records. Fix usage of limited discoverable mode. Remove deprecated methods and signals for AudioSource. ver 4.46: Add support for A2DP sink role. Fix clearing svc_cache before the adapter is up. Fix various pointer after free usages. Fix various memory leaks. ver 4.45: Fix UDEV_DATADIR fallback if pkg-config fails. Fix adapter cleanup and setup prototypes. Fix double-free with out-of-range devices. Fix inband ring setting to be per-headset. Fix handling of Maemo CSD startup. ver 4.44: Add some missing manual pages. Fix missing number prefix when installing udev rules. Fix program prefix used in Bluetooth udev rules. Fix three-way calling indicator order. Fix downgrade/upgrade of callheld indicator. Fix +CIEV sending when indicator value changes. Fix signal handling for Maemo telephony driver. Fix parsing issues with messages from Maemo CSD. Fix issue with duplicate active calls. ver 4.43: Add support for udev based on-demand startup. Fix verbose error reporting of CUPS backend. Fix various string length issues. Fix issues with Maemo telephony driver. Fix another device setup and temporary flag issue. Fix and update example agent implementation. ver 4.42: Add TI WL1271 to Texas Instruments chip list. Add special udev mode to bluetoothd. Fix regression when there is no agent registered. Fix error return when bonding socket hang up. Fix SCO server socket for HFP handsfree role. Fix shutdown on SCO socket before closing. Fix shutdown on A2DP audio stream channel before closing. Fix issue with asserting on AVDTP reference count bugs. Fix authorization denied issue with certain headsets. Fix AVRCP UNITINFO and SUBUNIT INFO responses. Fix discovery cancel issues in case SDP discovery fails. ver 4.41: Fix pairing even if the ACL gets dropped before successful SDP. Fix regression which caused device to be removed after pairing. Fix HSP record fetching when remote device doesn't support it. Fix SDP discovery canceling when clearing hs->pending. Fix headset never connecting on the first attempt. Fix headset state tracking if bt_search_service() fails. Fix maximum headset connection count check. Fix AVDTP Discover timeout handling. Fix also UI_SET_KEYBIT for the new pause and play key codes. ver 4.40: Add telephony driver for oFono telephony stack. Add support for Dell specific HID proxy switching. Add support for running hid2hci from udev. Add mapping for AVRCP Play and Pause to dedicated key codes. Fix AVRCP keycodes to better match existing X keymap support. Fix various quoting issues within telephony support. Fix memory allocation issue when generating PDUs for SDP. Fix race condition on device removal. Fix non-cancelable issue with CreateDevice method. Fix non-working CancelDiscovery method call. ver 4.39: Add workaround for dealing with unknown inquiry complete. Fix discovering when using software scheduler. Fix wrong NoInputNoOutput IO capability string. Fix race condition with agent during pairing. Fix agent cancellation for security mode 3 acceptor failure. Fix temporary flag removal when device creation fails. Fix hciattach to use ppoll instead of poll. Fix service class update when adapter is down. Fix service classes race condition during startup. Fix release of audio client before freeing the device. ver 4.38: Add support for builtin plugins. Add framework for adapter operations. Add constants for Enhanced Retransmission modes. Fix HCI socket leak in device_remove_bonding. Fix various format string issues. Fix crashes with various free functions. Fix issues with Headset and A2DP drivers to load again. Fix sending AVRCP button released passthrough messages Fix bug which prevent input devices to work after restart. Fix issue with interpretation of UUID-128 as channel. ver 4.37: Add version value for Bluetooth 3.0 devices. Add additional L2CAP extended feature mask bits. Add support for loading plugins in priority order. Add support for more detailed usage of disconnect watches. Add support for AVRCP volume control. Add saturated clipping of SBC decoder output to 16-bit. Fix potentially infinite recursion of adapter_up. Fix SCO handling in the case of an incoming call. Fix input service to use confirm callback. Fix cleanup of temporary device entries from storage. ver 4.36: Add proper tracking of AVCTP connect attempts. Add support to channel pattern in Serial interface. Fix A2DP sink crash if removing device while connecting. Fix error handling if HFP indicators aren't initialized. Fix segfault while handling an incoming SCO connection. Fix Serial.Disconnect to abort connection attempt. ver 4.35: Add support for Handsfree profile headset role. Add additional checks for open SEIDs from clients. Fix device removal while audio IPC client is connected. Fix device removal when an authorization request is pending. Fix incoming AVDTP connect while authorization in progress. Fix disconnection timers for audio support. Fix various potential NULL pointer deferences. Fix callheld indicator value for multiple calls. Fix voice number type usage. Fix GDBus watch handling. ver 4.34: Add support for version checks of plugins. Add support for class property on adapter interface. Add support for second SDP attempt after connection reset. Add support for more detailed audio states. Add support for HFP+A2DP auto connection feature. Add support for new and improved audio IPC. Add program for testing audio IPC interface. Fix various AVDTP qualification related issues. Fix broken SDP AttributeIdList parsing. Fix invalid memory access of SDP URL handling. Fix local class of device race conditions. Fix issue with periodic inquiry on startup. Fix missing temporary devices in some situations. Fix SBC alignment issue for encoding with four subbands. ver 4.33: Add Paired property to the DeviceFound signals. Add support for Headset profile 1.2 version. Fix broken network configuration when IPv6 is disabled. Fix network regression that caused disconnection. Fix SDP truncation of strings with NULL values. Fix service discovery handling of CUPS helper. ver 4.32: Fix broken SDP record handling. Fix SDP data buffer parsing. Fix more SDP memory leaks. Fix read scan enable calls. Fix A2DP stream handling. ver 4.31: Add support for new BtIO helper library. Fix AVDTP session close issue. Fix SDP memory leaks. Fix various uninitialized memory issues. Fix duplicate signal emissions. Fix property changes request handling. Fix class of device storage handling. ver 4.30: Add CID field to L2CAP socket address structure. Fix reset of authentication requirements after bonding. Fix storing of link keys when using dedicated bonding. Fix storing of pre-Bluetooth 2.1 link keys. Fix resetting trust settings on every reboot. Fix handling of local name changes. Fix memory leaks in hciconfig and hcitool ver 4.29: Use AVRCP version 1.0 for now. Decrease AVDTP idle timeout to one second. Delay AVRCP connection when remote device connects A2DP. Add workaround for AVDTP stream setup with broken headsets. Add missing three-way calling feature bit for Handsfree. Fix handsfree callheld indicator updating. Fix parsing of all AT commands within the buffer. Fix authentication replies when disconnected. Fix handling of debug combination keys. Fix handling of changed combination keys. Fix handling of link keys when using no bonding. Fix handling of invalid/unknown authentication requirements. Fix closing of L2CAP raw socket used for dedicated bonding. ver 4.28: Add AVDTP signal fragmentation support. Add more SBC performance optimizations. Add more SBC audio quality improvements. Use native byte order for audio plugins. Set the adapter alias only after checking the EIR data. Fix auto-disconnect issue with explicit A2DP connections. Fix invalid memory access of ALSA plugin. Fix compilation with -Wsign-compare. ver 4.27: Add more SBC optimization (MMX and ARM NEON). Add BT_SECURITY and BT_DEFER_SETUP definitions. Add support for deferred connection setup. Add support for fragmentation of data packets. Add option to trigger dedicated bonding. Follow MITM requirements from remote device. Require MITM for dedicated bonding if capabilities allow it. Fix IO capabilities for non-pairing and pairing cases. Fix no-bonding connections in non-bondable mode. Fix new pairing detection with SSP. Fix bonding with pre-2.1 devices and newer kernels. Fix LIAC setting while toggling Pairable property. Fix device creation for incoming security mode 3 connects. Fix crash within A2DP with bogus pointer. Fix issue with sdp_copy_record() function. Fix crash with extract_des() if sdp_uuid_extract() fails. ver 4.26: Use of constant shift in SBC quantization code. Add possibility to analyze 4 blocks at once in encoder. Fix correct handling of frame sizes in the encoder. Fix for big endian problems in SBC codec. Fix audio client socket to always be non-blocking. Update telephony support for Maemo. ver 4.25: Fix receiving data over the audio control socket. Fix subbands selection for joint-stereo in SBC encoder. Add new SBC analysis filter function. ver 4.24: Fix signal emissions when removing adapters. Fix missing adapter signals on exit. Add support for bringing adapters down on exit. Add support for RememberPowered option. Add support for verbose compiler warnings. Add more options to SBC encoder. ver 4.23: Update audio IPC for better codec handling. Fix bitstream optimization for SBC encoder. Fix length header values of IPC messages. Fix multiple coding style violations. Fix FindDevice to handle temporary devices. Add configuration option for DeviceID. Add support for InitiallyPowered option. Add missing signals for manager properties. Add telephony support for Maemo. ver 4.22: Add deny statements to D-Bus access policy. Add support for LegacyPairing property. Add support for global properties. Add more commands to telephony testing script. Add sender checks for serial and network interfaces. Remove deprecated methods and signals from input interface. Remove deprecated methods and signals from network interface. Remove OffMode option and always use device down. ver 4.21: Fix adapter initialization logic. Fix adapter setup and start security manager early. Fix usage issue with first_init variable. ver 4.20: Cleanup session handling. Cleanup mode setting handling. Fix issue with concurrent audio clients. Fix issue with HFP/HSP suspending. Fix AT result code syntax handling. Add Handsfree support for AT+NREC. Add PairableTimeout adapter property. ver 4.19: Fix installation of manual pages for old daemons. Fix D-Bus signal emmissions for CreateDevice. Fix issues with UUID probing. Fix +BSRF syntax issue. Add Pairable adapter property. Add sdp_copy_record() library function. ver 4.18: Fix release before close issue with RFCOMM TTYs. Fix Connected property on input interface. Fix DeviceFound signals during initial name resolving. Fix service discovery handling. Fix duplicate UUID detection. Fix SBC gain mismatch and decoding handling. Add more options to SBC encoder and decoder. Add special any adapter object for service interface. Add variable prefix to adapter and device object paths. ver 4.17: Fix SBC encoder not writing last frame. Fix missing timer for A2DP suspend. Add more supported devices to hid2hci utility. Add additional functionality to Handsfree support. ver 4.16: Fix wrong parameter usage of watch callbacks. Fix parameters for callback upon path removal. Fix unloading of adapter drivers. ver 4.15: Fix various A2DP state machine issues. Fix some issues with the Handsfree error reporting. Fix format string warnings with recent GCC versions. Remove dependency on GModule. ver 4.14: Fix types of property arrays. Fix potential crash with input devices. Fix PS3 BD remote input event generation. Allow dynamic adapter driver registration. Update udev rules. ver 4.13: Fix service discovery and UUID handling. Fix bonding issues with Simple Pairing. Fix file descriptor misuse of SCO connections. Fix various memory leaks in the device handling. Fix AVCTP disconnect handling. Fix GStreamer modes for MP3 encoding. Add operator selection to Handsfree support. ver 4.12: Fix crash with missing icon value. Fix error checks of HAL plugin. Fix SCO server socket cleanup on exit. Fix memory leaks from DBusPendingCall. Fix handling of pending authorization requests. Fix missing protocol UUIDs in record pattern. ver 4.11: Change SCO server socket into a generic one. Add test script for dummy telephony plugin. Fix uninitialized reply of multiple GetProperties methods. ver 4.10: Fix memory leaks with HAL messages. Add more advanced handsfree features. Add properties to audio, input and network interfaces. Stop device discovery timer on device removal. ver 4.9: Fix signals for Powered and Discoverable properties. Fix handling of Alias and Icon properties. Fix duplicate entries for service UUIDs. ver 4.8: Fix retrieving of formfactor value. Fix retrieving of local and remote extended features. Fix potential NULL pointer dereference during pairing. Fix crash with browsing due to a remotely initated pairing. ver 4.7: Fix pairing and service discovery logic. Fix crashes during suspend and resume. Fix race condition within devdown mode. Add RequestSession and ReleaseSession methods. Add Powered and Discoverable properties. Add Devices property and deprecate ListDevices. Add workaround for a broken carkit from Nokia. ver 4.6: Fix Device ID record handling. Fix service browsing and storage. Fix authentication and encryption for input devices. Fix adapter name initialization. ver 4.5: Fix initialization issue with new adapters. Send HID authentication request without blocking. Hide the verbose SDP debug behind SDP_DEBUG. Add extra UUIDs for service discovery. Add SCO server socket listener. Add authorization support to service plugin. ver 4.4: Add temporary fix for the CUPS compile issue. Add service-api.txt to distribution. Mention the variable prefix of an object path ver 4.3: Add dummy driver for telephony support. Add support for discovery sessions. Add service plugin for external services. Various cleanups. ver 4.2: Avoid memory copies in A2DP write routine. Fix broken logic with Simple Pairing check and old kernels. Allow non-bondable and outgoing SDP without agent. Only remove the bonding for non-temporary devices. Cleanup various unnecessary includes. Make more unexported functions static. Add basic infrastructure for gtk-doc support. ver 4.1: Add 30 seconds timeout to BNEP connection setup phase. Avoid memory copies in A2DP write routine for ALSA. Make sure to include compat/sdp.h in the distribution. ver 4.0: Initial public release. ver 3.36: Add init routines for TI BRF chips. Add extra attributes to the serial port record. Add example record for headset audio gateway record. Use Handsfree version 0x0105 for the gateway role. Fix SDP record registration with specific record handles. Fix BCSP sent/receive handling. Fix various includes for cross-compilation. Allow link mode settings for outgoing connections. Allow bonding during periodic inquiry. ver 3.35: Add two additional company identifiers. Add UUID-128 support for service discovery. Fix usage of friendly names for service discovery. Fix authorization when experiemental is disabled. Fix uninitialized variable in passkey request handling. Enable output of timestamps for l2test and rctest. ver 3.34: Replace various SDP functions with safe versions. Add additional length validation for incoming SDP packets. Use safe function versions for SDP client handling. Fix issue with RemoveDevice during discovery procedure. Fix collect for non-persistent service records. ver 3.33: Add functions for reading and writing the link policy settings. Add definition for authentication requirements. Add support for handling Simple Pairing. Add Simple Pairing support to Agent interface. Add ReleaseMode method to Adapter interface. Add DiscoverServices method to Device interface. Remove obsolete code and cleanup the repository. Move over to use the libgdbus API. Enable PIE by default if supported. ver 3.32: Add OCF constants for synchronous flow control enabling. Add support for switching HID proxy devices from Dell. Add more Bluetooth client/server helper functions. Add support for input service idle timeout option. Fix BNEP reconnection handling. Fix return value for snd_pcm_hw_params() calls. Use upper-case addresses for object paths. Remove HAL support helpers. Remove inotify support. Remove service daemon activation handling. Remove uneeded D-Bus API extension. ver 3.31: Create device object for all pairing cases. Convert authorization to internal function calls. Add initial support for Headset Audio Gateway role. Add generic Bluetooth helper functions for GLib. Fix endiannes handling of connection handles. Don't optimize when debug is enabled. ver 3.30: Convert audio service into a plugin. Convert input service into a plugin. Convert serial service into a plugin. Convert network service into a plugin. Emit old device signals when a property is changed. Fix missing DiscoverDevices and CancelDiscovery methods. Add another company identifier. Add basic support for Bluetooth sessions. Add avinfo utility for AVDTP/A2DP classification. Remove build option for deprecated sdpd binary. ver 3.29: Introduce new D-Bus based API. Add more SBC optimizations. Add support for PS3 remote devices. Fix alignment trap in SDP server. Fix memory leak in sdp_get_uuidseq_attr function. ver 3.28: Add support for MCAP UUIDs. Add support for role switch for audio service. Add disconnect timer for audio service. Add disconnect detection to ALSA plugin. Add more SBC optimizations. Fix alignment issue of SDP server. Remove support for SDP parsing via expat. ver 3.27: Update uinput.h with extra key definitions. Add support for input connect/disconnect callbacks. Add ifdefs around some baud rate definitions. Add another company identifier. Add proper HFP service level connection handling. Add basic headset automatic disconnect support. Add support for new SBC API. Fix SBC decoder noise at high bitpools. Use 32-bit multipliers for further SBC optimization. Check for RFCOMM connection state in SCO connect callback. Make use of parameters selected in ALSA plugin. ver 3.26: Fix compilation issues with UCHAR_MAX, USHRT_MAX and UINT_MAX. Improve handling of different audio transports. Enable services by default and keep old daemons disabled. ver 3.25: Add limited support for Handsfree profile. Add limited support for MPEG12/MP3 codec. Add basic support for UNITINFO and SUBUNITINFO. Add more SBC optimizations. Fix external service (un)registration. Allow GetInfo and GetAddress to fail. ver 3.24: Add definitions for MDP. Add TCP connection support for serial proxy. Add fix for Logitech HID proxy switching. Add missing macros, MIN, MAX, ABS and CLAMP. Add more SBC encoder optimizations. Add initial mechanism to handle headset commands. Fix connecting to handsfree profile headsets. Use proper function for checking signal name. ver 3.23: Fix remote name request handling bug. Fix key search function to honor the mmap area size. Fix Avahi integration of network service. Add new plugin communication for audio service. Enable basic AVRCP support by default. More optimizations to the SBC library. Create common error definitions. ver 3.22: Add missing include file from audio service. Add SBC conformance test utility. Add basic uinput support for AVRCP. Fix L2CAP socket leak in audio service. Fix buffer usage in GStreamer plugin. Fix remote name request event handling. ver 3.21: Add constant for Bluetooth socket options level. Add initial AVRCP support. Add A2DP sink support to GStreamer plugin. Fix interoperability with A2DP suspend. Fix sign error in 8-subband encoder. Fix handling of service classes length size. Store Extended Inquiry Response data information. Publish device id information through EIR. Support higher baud rates for Ericcson based chips. ver 3.20: Fix GStreamer plugin file type detection. Fix potential infinite loop in inotify support. Fix D-Bus signatures for dict handling. Fix issues with service activation. Fix SDP failure handling of audio service. Fix various memory leaks in input service. Add secure device creation method to input service. Add service information methods to serial service. Add config file support to network service. Add scripting capability to network service. Add special on-mode handling. Add optimization for SBC encoder. Add tweaks for D-Bus 1.1.x libraries. Add support for inquiry transmit power level. ver 3.19: Limit range of bitpool announced while in ACP side. Use poll instead of usleep to wait for worker thread. Use default event mask from the specification. Add L2CAP mode constants. Add HID proxy support for Logitech diNovo Edge dongle. Add refresh option to re-request device names. Show correct connection link type. ver 3.18: Don't allocate memory for the Bluetooth base UUID. Implement proper locking for headsets. Fix various A2DP SEP locking issues. Fix and cleanup audio stream handling. Fix stream starting if suspend request is pending. Fix A2DP and AVDTP endianess problems. Add network timeout and retransmission support. Add more detailed decoding of EIR elements. ver 3.17: Fix supported commands bit calculation. Fix crashes in audio and network services. Check PAN source and destination roles. Only export the needed symbols for the plugins. ver 3.16: Update company identifier list. Add support for headsets with SCO audio over HCI. Add support for auto-create through ALSA plugin. Add support for ALSA plugin parameters. Add GStreamer plugin with SBC decoder and encoder. Fix network service NAP, GN and PANU servers. Set EIR information from SDP database. ver 3.15: Add A2DP support to the audio service. Add proxy support to the serial service. Extract main service class for later use. Set service classes value from SDP database. ver 3.14: Add missing signals for the adapter interface. Add definitions and functions for Simple Pairing. Add basic commands for Simple Pairing. Add correct Simple Pairing and EIR interaction. Add missing properties for remote information. Add EPoX endian quirk to the input service. Fix HID descriptor import and storage functions. Fix handling of adapters in raw mode. Fix remote device listing methods. ver 3.13: Fix some issues with the headset support. Fix concurrent pending connection attempts. Fix usage of devname instead of netdev. Add identifier for Nokia SyncML records. Add command for reading the CSR chip revision. Add generic CSR radio test support. Update HCI command table. ver 3.12: Add missing HCI command text descriptions Add missing HCI commands structures. Add missing HCI event structures. Add common bachk() function. Add support for limited discovery mode. Add support for setting of event mask. Add GetRemoteServiceIdentifiers method. Add skeleton for local D-Bus server. Add headset gain control methods. Fix various headset implementation issues. Fix various serial port service issues. Fix various input service issues. Let CUPS plugin discover printers in range. Improve the BCM2035 UART init routine. Ignore connection events for non-ACL links. ver 3.11: Update API documentation. Minimize SDP root records and browse groups. Use same decoder for text and URL strings. Fix URL data size handling. Fix SDP pattern extraction for XML. Fix network connection persistent state. Add network connection helper methods. Add initial version of serial port support. Add class of device tracking. ver 3.10.1: Add option to disable installation of manual pages. Fix input service encryption setup. Fix serial service methods. Fix network service connection handling. Provide a simple init script. ver 3.10: Add initial version of network service. Add initial version of serial service. Add initial version of input service. Add initial version of audio service. Add authorization framework. Add integer based SBC library. Add version code for Bluetooth 2.1 specification. Add ESCO_LINK connection type constant. Export sdp_uuid32_to_uuid128() function. ver 3.9: Add RemoteDeviceDisconnectRequested signal. Add updated service framework. Add embedded GLib library. Add support for using system GLib library. Create internal SDP server library. ver 3.8: Sort discovered devices list based on their RSSI. Send DiscoverableTimeoutChanged signal. Fix local and remote name validity checking. Add ListRemoteDevices and ListRecentRemoteDevices methods. Add basic integration of confirmation concept. Add support for service record description via XML. Add support for external commands to the RFCOMM utility. Add experimental service and authorization API. Add functions for registering binary records. ver 3.7: Fix class of device handling. Fix error replies with pairing and security mode 3. Fix disconnect method for RFCOMM connections. Add match pattern for service searches. Add support for prioritized watches. Add additional PDU length checks. Fix CSRC value for partial responses. ver 3.6.1: Fix IO channel race conditions. Fix pairing issues on big endian systems. Fix pairing issues with page timeout errors. Fix pairing state for security mode 3 requests. Switch to user as default security manager mode. ver 3.6: Update D-Bus based RFCOMM interface support. Use L2CAP raw sockets for HCI connection creation. Add periodic discovery support to the D-Bus interface. Add initial support for device names via EIR. Add proper UTF-8 validation of device names. Add support for the J-Three keyboard. Fix issues with the asynchronous API for SDP. ver 3.5: Fix and cleanup watch functionality. Add support for periodic inquiry mode. Add support for asynchronous SDP requests. Add more request owner tracking. Add asynchronous API for SDP. Document pageto and discovto options. ver 3.4: Improve error reporting for failed HCI commands. Improve handling of CancelBonding. Fixed bonding reply message when disconnected. Fix UUID128 string lookup handling. Fix malloc() versus bt_malloc() usage. ver 3.3: Don't change inquiry mode for Bluetooth 1.1 adapters. Add udev rules for Bluetooth serial PCMCIA cards. Add Cancel and Release methods for passkey agents. Add GetRemoteClass method. Convert to using ppoll() and pselect(). Initialize allocated memory to zero. Remove bcm203x firmware loader. Remove kernel specific timeouts. Add additional private data field for SDP sessions. Add host controller to host flow control defines. Add host number of completed packets defines. Initialize various memory to zero before usage. ver 3.2: Only check for the low-level D-Bus library. Update possible device minor classes. Fix timeout for pending reply. Add more Inquiry with RSSI quirks. Sleep only 100 msecs for device detection. Don't send BondingCreated on link key renewal. Allow storing of all UTF-8 remote device names. Create storage filenames with a generic function. Fix handling of SDP strings. Add adapter type for SDIO cards. Add features bit for link supervision timeout. ver 3.1: Add missing placeholders for feature bits. Fix handling of raw mode devices. Fix busy loop in UUID extraction routine. Remove inquiry mode setting. Remove auth and encrypt settings. ver 3.0: Implement the new BlueZ D-Bus API. Fix broken behavior with EVT_CMD_STATUS. Add features bit for pause encryption. Add additional EIR error code. Add more company identifiers. Add another Phonebook Access identifier. Update sniff subrating data structures. ver 2.25: Use %jx instead of %llx for uint64_t and int64_t. Allow null-terminated text strings. Add UUID for N-Gage games. Add UUID for Apple Macintosh Attributes. Add Apple attributes and iSync records. Add definitions for Apple Agent. Add support for the Handsfree Audio Gateway service. Add support for choosing a specific record handle. Add support for dialup/telephone connections. Add definitions for Apple Agent. Add support for record handle on service registration. ver 2.24: Fix display of SDP text and data strings. Add support for device scan property. Add support for additional access protocols. Update the D-Bus policy configuration file. ver 2.23: Update the new D-Bus interface. Make dfutool ready for big endian architectures. Add support for AVRCP specific service records. Add support for writing complex BCCMD commands. Add the new BCCMD interface utility. Add MicroBCSP implementation from CSR. Add constants and definitions for sniff subrating. Add support for allocation of binary text elements. Add HCI emulation tool. Add fake HID support for old EPoX presenters. Reject connections from unknown HID devices. Fix service discovery deadlocks with Samsung D600 phones. ver 2.22: Remove D-Bus 0.23 support. Add initial version of the new D-Bus interface. Add support for extended inquiry response commands. Add support for the Logitech diNovo Media Desktop Laser. Add compile time buffer checks (FORTIFY SOURCE). Decode reserved LMP feature bits. Fix errno overwrite problems. Fix profile descriptor problem with Samsung phones. ver 2.21: Move create_dirs() and create_file() into the textfile library. Let textfile_put() also replace the last key value pair. Fix memory leaks with textfile_get() usage. Fix infinite loops and false positive matches. Don't retrieve stored link keys for RAW devices. Document the putkey and delkey commands. Show supported commands also in clear text. Support volatile changes of the BD_ADDR for CSR chips. Add support for identification of supported commands. Add missing OCF declarations for the security filter. Add two new company identifiers. ver 2.20: Add UUIDs for video distribution profile. Add UUIDs for phonebook access profile. Add attribute identifier for supported repositories. Add definitions for extended inquiry response. Add functions for extended inquiry response. Add support for extended inquiry response. Add support for HotSync service record. Add support for ActiveSync service record. Add ActiveSync networking support. Fix D-Bus crashes with new API versions. ver 2.19: Fix the GCC 4.0 warnings. Fix the routing for dealing with raw devices. Fix off by one memory allocation error. Fix security problem with escape characters in device name. Add per device service record functions. Send D-Bus signals for inquiry results and remote name resolves. Add support for device specific SDP records. ver 2.18: Support D-Bus 0.23 and 0.33 API versions. Support reading of complex BCCMD values. Support minimum and maximum encryption key length. Add support for reading and writing the inquiry scan type. Add definitions for connection accept timeout and scan enable. Add support for inquiry scan type. Add tool for the CSR BCCMD interface. Add first draft of the Audio/Video control utility. Add disconnect timer support for the A2DP ALSA plugin. Make SBC parameters configurable. Replace non-printable characters in device names. Remove hci_vhci.h header file. Remove hci_uart.h header file. ver 2.17: Set the storage directory through ${localstatedir}. Add the textfile library for ASCII based file access. Add support for return link keys event. Add support for voice setting configuration. Add support for page scan timeout configuration. Add support for storing and deleting of stored link keys. Add support for searching for services with UUID-128. Add support for retrieving all possible service records. Add support for a raw mode view of service records. Add support for HID information caching in hidd. Add support for authentication in pand and dund. Add support for changing BD_ADDR of CSR chips. Add pskey utility for changing CSR persistent storage values. Add the firmware upgrade utility. Add connection caching for the A2DP ALSA plugin. Add functions for stored link keys. Add definitions for PIN type and unit key. Add SDP_WAIT_ON_CLOSE flag for sdp_connect(). Include stdio.h in bluetooth.h header file. Include sys/socket.h in the header files. ver 2.16: Store link keys in ASCII based file format. Support device name caching. Support zero length data sizes in l2test. Change default l2ping data size to 44 bytes. Hide the server record and the public browse group root. Read BD_ADDR if not set and if it is a raw device. Add SDP language attributes. Add support for browsing the L2CAP group. Add support for stored pin codes for outgoing connections. Add support for local commands and extended features. Add support for reading CSR panic and fault codes. Add config option for setting the inquiry mode. Add OUI decoding support. Use unlimited inquiry responses as default. Use cached device names for PIN request. Use the clock offset when getting the remote names. Add function for reading local supported commands. Add function for reading local extended features. Add function for reading remote extended features. Add function for getting the remote name with a clock offset. Add function for extracting the OUI from a BD_ADDR. Add inquiry info structure with RSSI and page scan mode. Fix buffer allocation for features to string conversion. Support inquiry with unlimited number of responses. ver 2.15: Enable the RFCOMM service level security. Add deprecated functions for reading the name. Add command for reading the clock offset. Add command for reading the clock. Add function for reading the clock. Add function for reading the local Bluetooth address. Add function for reading the local supported features. Don't configure raw devices. Don't set inquiry scan or page scan on raw devices. Don't show extended information for raw devices. Support L2CAP signal sizes bigger than 2048 bytes. Cleanup of the socket handling code of the test programs. Use better way for unaligned access. Remove sdp_internal.h and its usage. ver 2.14: Make use of additional connection information. Use library function for reading the RSSI. Use library function for reading the link quality. Use library function for reading the transmit power level. Use library functions for the link supervision timeout. Add tool for changing the device address. Add function for reading the RSSI. Add function for reading the link quality. Add function for reading the transmit power level. Add functions for the link supervision timeout. Remove deprecated functions. Update AM_PATH_BLUEZ macro. ver 2.13: Use file permission 0600 for the link key file. Add support for HID attribute descriptions. Add support for Device ID attributes. Add Device ID and HID attribute definitions. Update the UUID constants and its translations. Update L2CAP socket option definitions. Update connection information definitions. Various whitespace cleanups. ver 2.12: Inherit the device specific options from the default. Use --device for selecting the source device. Add --nosdp option for devices with resource limitation. Add support and parameter option for secure mode. Add a lot of build ids and hardware revisions. Add service classes and profile ids for WAP. Add simple AM_PATH_BLUEZ macro. Update UUID translation tables. Correct kernel interface for CMTP and HIDP support. ver 2.11: Initial support for the kernel security manager. Various cleanups to avoid inclusion of kernel headers. Fix output when the CUPS backend is called without arguments. Fix problems with a 64 bit userland. Use Bluetooth library functions if available. Use standard numbering scheme of SDP record handles. Use bit zero for vendor packets in the filter type bitmask. Add SIM Access types for service discovery. Add more audio/video profile translations. Add another company identifier. Add the missing HCI error codes. Add RFCOMM socket options. Add definition for the SECURE link mode. Add functions for reading and writing the inquiry mode. Add functions for AFH related settings and information. Add version identifier for the Bluetooth 2.0 specification. Add a master option to the hidd. Add support for changing the link key of a connection. Add support for requesting encryption on keyboards. Add support for revision information of Digianswer devices. Add support for the Zoom, IBM and TDK PCMCIA cards. Add checks for the OpenOBEX and the ALSA libraries. Add experimental mRouter support. ver 2.10: Use a define for the configuration directory. Fix string initialization for flags translation. Fix and extend the unaligned access macros. Make compiling with debug information optional. Don't override CFLAGS from configure. Check for usb_get_busses() and usb_interrupt_read(). Add optional support for compiling with PIE. Make installation of the init scripts optional. Make compiling with debug information optional. Don't override CFLAGS from configure. ver 2.9: Retry SDP connect if busy in the CUPS backend. Use packet type and allow role switch in hcitool. Use the functions from the USB library for hid2hci. Add Broadcom firmware loader. Add EPoX endian quirk for buggy keyboards. Add L2CAP info type and info result definitions. Add value for L2CAP_CONF_RFC_MODE. Change RSSI value to signed instead of unsigned. Allow UUID32 values as protocol identifiers. Update the autoconf/automake scripts. ver 2.8: Use LIBS and LDADD instead of LDFLAGS. Use HIDP subclass field for HID boot protocol. Set olen before calling getsockopt() in pand. Restore signals for dev-up script. Add PID file support for pand. Add size parameter to expand_name() in hcid. Add support for audio source and audio sink SDP records. Add support for HID virtual cable unplug. Add support for AmbiCom BT2000C card. Add defines and UUID's for audio/video profiles. Add AVDTP protocol identifier. Add HIDP subclass field. Add PKGConfig support. Fix the event code of inquiry with RSSI. Remove dummy SDP library. ver 2.7: Fix display of decoded LMP features. Update company identifiers. Add AFH related types. Add first bits from EDR prototyping specification. Add support for inquiry with RSSI. Add HCRP related SDP functions. Add HIDP header file. Add support for getting the AFH channel map. Add support for AFH mode. Add support for inquiry mode. Add Bluetooth backend for CUPS. Add the hid2hci utility. Add the hidd utility. Add the pand utility. Add the dund utility. More endian bug fixes. Give udev some time to create the RFCOMM device nodes. Release the TTY if no device node is found. New startup script for the Bluetooth subsystem. Update to the autoconf stuff. ver 2.6: Change default prefix to /usr. Add manpages for hcid and hcid.conf. Add the sdpd server daemon. Add the sdptool utility. Add the ciptool utility. Add new company identifiers. Add BNEP and CMTP header files. Add the SDP library. Use R2 for default value of pscan_rep_mode. ver 2.5: Add decoding of Bluetooth 1.2 features. Add link manager version parameter for Bluetooth 1.2. Add new company identifiers. Add D-Bus support for PIN request. Support for transmit power level. Support for park, sniff and hold mode. Support for role switch. Support for reading the clock offset. Support for requesting authentication. Support for setting connection encryption. Show revision information for Broadcom devices. Replace unprintable characters in device name. Use R1 for default value of pscan_rep_mode. Fix some 64-bit problems. Fix some endian problems. Report an error on PIN helper failure. Update bluepin script for GTK2. ver 2.4: Increase number of inquiry responses. Support for transmit power level. Display all 8 bytes of the features. Add support for reading and writing of IAC. Correct decoding class of device. Use Ericsson revision command for ST Microelectronics devices. Display AVM firmware version with 'revision' command. New code for CSR specific revision information. Support for ST Microelectronics specific initialization. Support for 3Com card version 3.0. Support for TDK, IBM and Socket cards. Support for initial baud rate. Update man pages. Fixes for some memory leaks. ver 2.3: Added const qualifiers to appropriate function arguments. Minor fixes. CSR firmware version is now displayed by 'revision' command. Voice command is working properly on big endian machines. Added support for Texas Bluetooth modules. Added support for high UART baud rates on Ericsson modules. BCSP initialization fixes. Support for role switch command (hcitool). RFCOMM config file parser fixes. Update man pages. Removed GLib dependency. ver 2.2: Updated RFCOMM header file. Additional HCI command and event defines. Support for voice settings (hciconfig). Minor hcitool fixes. Improved configure script. Added Headset testing tool. Updated man pages. RPM package. ver 2.1.1: Resurrect hci_remote_name. ver 2.1: Added hci_{read, write}_class_of_dev(). Added hci_{read, write}_current_iac_lap(). Added hci_write_local_name(). Added RFCOMM header file. Minor fixes. Improved BCSP initialization (hciattach). Support for displaying link quality (hcitool). Support for changing link supervision timeout (hcitool). New RFCOMM TTY configuration tool (rfcomm). Minor fixes and updates. ver 2.0: Additional company IDs. BCSP initialization (hciattach). Minor hciconfig fixes. ver 2.0-pr13: Support for multiple pairing modes. Link key database handling fixes. ver 2.0-pre12: Removed max link key limit. Keys never expire. Link key database is always updated. Reread PIN on SIGHUP (hcid). Bluetooth script starts SDPd, if installed. Other minor fixes. ver 2.0-pre11: Improved link key management and more verbose logging (hcid). Fixed scan command (hcitool). ver 2.0-pre10: Fix hci_inquiry function to return errors and accept user buffers. New functions hci_devba, hci_devid, hci_for_each_dev and hci_get_route. Additional company IDs. Makefile and other minor fixes. Support for reading RSSI, remote name and changing connection type (hcitool). Device initialization fixes (hcid). Other minor fixes and improvements. Build environment cleanup and fixes. ver 2.0-pre9: Improved bluepin. Working X authentication. Improved hcitool. New flexible cmd syntax, additional commands. Human readable display of the device features. LMP features to string translation support. Additional HCI command and event defines. Extended hci_filter API. ver 2.0-pre8: Additional HCI ioctls and defines. All strings and buffers are allocated dynamically. ba2str, str2ba automatically swap bdaddress. Additional hciconfig commands. Support for ACL and SCO MTU ioctls. Support for Inventel and COM1 UART based devices. Minor hcitool fixes. Improved l2test. New L2CAP test modes. Minor fixes and cleanup. ver 2.0-pre7: Bluetooth libraries and header files is now a separate package. New build environment uses automake and libtool. Massive header files cleanup. Bluetooth utilities is now a separate package. New build environment uses automake. Moved all config files and security data to /etc/bluetooth. Various cleanups. ver 2.0-pre6: API cleanup and additions. Improved hcitool. l2test minor output fixes. hciattach opt to display list of supported devices. ver 2.0-pre4: HCI filter enhancements. ver 2.0-pre3: Cleanup. ver 2.0-pre2: Additional HCI library functions. Improved CSR baud rate initialization. PCMCIA scripts fixes and enhancements. Documentation update. ver 2.0-pre1: New UART initialization utility. Hot plugging support for UART based PCMCIA devices. SCO testing utility. New authentication utility (bluepin). Minor fixes and improvements. bluez-4.101/gdbus/0000755000000000000000000000000011771120004010704 500000000000000bluez-4.101/gdbus/polkit.c0000644000000000000000000001262011571052274012306 00000000000000/* * * D-Bus helper library * * Copyright (C) 2004-2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include int polkit_check_authorization(DBusConnection *conn, const char *action, gboolean interaction, void (*function) (dbus_bool_t authorized, void *user_data), void *user_data, int timeout); static void add_dict_with_string_value(DBusMessageIter *iter, const char *key, const char *str) { DBusMessageIter dict, entry, value; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry); dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key); dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &value); dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str); dbus_message_iter_close_container(&entry, &value); dbus_message_iter_close_container(&dict, &entry); dbus_message_iter_close_container(iter, &dict); } static void add_empty_string_dict(DBusMessageIter *iter) { DBusMessageIter dict; dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict); dbus_message_iter_close_container(iter, &dict); } static void add_arguments(DBusConnection *conn, DBusMessageIter *iter, const char *action, dbus_uint32_t flags) { const char *busname = dbus_bus_get_unique_name(conn); const char *kind = "system-bus-name"; const char *cancel = ""; DBusMessageIter subject; dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &subject); dbus_message_iter_append_basic(&subject, DBUS_TYPE_STRING, &kind); add_dict_with_string_value(&subject, "name", busname); dbus_message_iter_close_container(iter, &subject); dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &action); add_empty_string_dict(iter); dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &flags); dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &cancel); } static dbus_bool_t parse_result(DBusMessageIter *iter) { DBusMessageIter result; dbus_bool_t authorized, challenge; dbus_message_iter_recurse(iter, &result); dbus_message_iter_get_basic(&result, &authorized); dbus_message_iter_get_basic(&result, &challenge); return authorized; } struct authorization_data { void (*function) (dbus_bool_t authorized, void *user_data); void *user_data; }; static void authorization_reply(DBusPendingCall *call, void *user_data) { struct authorization_data *data = user_data; DBusMessage *reply; DBusMessageIter iter; dbus_bool_t authorized = FALSE; reply = dbus_pending_call_steal_reply(call); if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) goto done; if (dbus_message_has_signature(reply, "(bba{ss})") == FALSE) goto done; dbus_message_iter_init(reply, &iter); authorized = parse_result(&iter); done: if (data->function != NULL) data->function(authorized, data->user_data); dbus_message_unref(reply); dbus_pending_call_unref(call); } #define AUTHORITY_DBUS "org.freedesktop.PolicyKit1" #define AUTHORITY_INTF "org.freedesktop.PolicyKit1.Authority" #define AUTHORITY_PATH "/org/freedesktop/PolicyKit1/Authority" int polkit_check_authorization(DBusConnection *conn, const char *action, gboolean interaction, void (*function) (dbus_bool_t authorized, void *user_data), void *user_data, int timeout) { struct authorization_data *data; DBusMessage *msg; DBusMessageIter iter; DBusPendingCall *call; dbus_uint32_t flags = 0x00000000; if (conn == NULL) return -EINVAL; data = dbus_malloc0(sizeof(*data)); if (data == NULL) return -ENOMEM; msg = dbus_message_new_method_call(AUTHORITY_DBUS, AUTHORITY_PATH, AUTHORITY_INTF, "CheckAuthorization"); if (msg == NULL) { dbus_free(data); return -ENOMEM; } if (interaction == TRUE) flags |= 0x00000001; if (action == NULL) action = "org.freedesktop.policykit.exec"; dbus_message_iter_init_append(msg, &iter); add_arguments(conn, &iter, action, flags); if (dbus_connection_send_with_reply(conn, msg, &call, timeout) == FALSE) { dbus_message_unref(msg); dbus_free(data); return -EIO; } if (call == NULL) { dbus_message_unref(msg); dbus_free(data); return -EIO; } data->function = function; data->user_data = user_data; dbus_pending_call_set_notify(call, authorization_reply, data, dbus_free); dbus_message_unref(msg); return 0; } bluez-4.101/gdbus/gdbus.h0000644000000000000000000001576111771117441012126 00000000000000/* * * D-Bus helper library * * Copyright (C) 2004-2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifndef __GDBUS_H #define __GDBUS_H #ifdef __cplusplus extern "C" { #endif #include #include typedef void (* GDBusWatchFunction) (DBusConnection *connection, void *user_data); typedef gboolean (* GDBusSignalFunction) (DBusConnection *connection, DBusMessage *message, void *user_data); DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name, DBusError *error); DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name, DBusError *error); gboolean g_dbus_request_name(DBusConnection *connection, const char *name, DBusError *error); gboolean g_dbus_set_disconnect_function(DBusConnection *connection, GDBusWatchFunction function, void *user_data, DBusFreeFunction destroy); typedef void (* GDBusDestroyFunction) (void *user_data); typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection, DBusMessage *message, void *user_data); typedef guint32 GDBusPendingReply; typedef void (* GDBusSecurityFunction) (DBusConnection *connection, const char *action, gboolean interaction, GDBusPendingReply pending); typedef enum { G_DBUS_METHOD_FLAG_DEPRECATED = (1 << 0), G_DBUS_METHOD_FLAG_NOREPLY = (1 << 1), G_DBUS_METHOD_FLAG_ASYNC = (1 << 2), } GDBusMethodFlags; typedef enum { G_DBUS_SIGNAL_FLAG_DEPRECATED = (1 << 0), } GDBusSignalFlags; typedef enum { G_DBUS_PROPERTY_FLAG_DEPRECATED = (1 << 0), } GDBusPropertyFlags; typedef enum { G_DBUS_SECURITY_FLAG_DEPRECATED = (1 << 0), G_DBUS_SECURITY_FLAG_BUILTIN = (1 << 1), G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION = (1 << 2), } GDBusSecurityFlags; typedef struct { const char *name; const char *signature; } GDBusArgInfo; typedef struct { const char *name; GDBusMethodFunction function; GDBusMethodFlags flags; unsigned int privilege; const GDBusArgInfo *in_args; const GDBusArgInfo *out_args; } GDBusMethodTable; typedef struct { const char *name; GDBusSignalFlags flags; const GDBusArgInfo *args; } GDBusSignalTable; typedef struct { const char *name; const char *type; GDBusPropertyFlags flags; } GDBusPropertyTable; typedef struct { unsigned int privilege; const char *action; GDBusSecurityFlags flags; GDBusSecurityFunction function; } GDBusSecurityTable; #define GDBUS_ARGS(args...) (const GDBusArgInfo[]) { args, { } } #define GDBUS_METHOD(_name, _in_args, _out_args, _function) \ .name = _name, \ .in_args = _in_args, \ .out_args = _out_args, \ .function = _function #define GDBUS_ASYNC_METHOD(_name, _in_args, _out_args, _function) \ .name = _name, \ .in_args = _in_args, \ .out_args = _out_args, \ .function = _function, \ .flags = G_DBUS_METHOD_FLAG_ASYNC #define GDBUS_DEPRECATED_METHOD(_name, _in_args, _out_args, _function) \ .name = _name, \ .in_args = _in_args, \ .out_args = _out_args, \ .function = _function, \ .flags = G_DBUS_METHOD_FLAG_DEPRECATED #define GDBUS_DEPRECATED_ASYNC_METHOD(_name, _in_args, _out_args, _function) \ .name = _name, \ .in_args = _in_args, \ .out_args = _out_args, \ .function = _function, \ .flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_DEPRECATED #define GDBUS_NOREPLY_METHOD(_name, _in_args, _out_args, _function) \ .name = _name, \ .in_args = _in_args, \ .out_args = _out_args, \ .function = _function, \ .flags = G_DBUS_METHOD_FLAG_NOREPLY #define GDBUS_SIGNAL(_name, _args) \ .name = _name, \ .args = _args #define GDBUS_DEPRECATED_SIGNAL(_name, _args) \ .name = _name, \ .args = _args, \ .flags = G_DBUS_SIGNAL_FLAG_DEPRECATED gboolean g_dbus_register_interface(DBusConnection *connection, const char *path, const char *name, const GDBusMethodTable *methods, const GDBusSignalTable *signals, const GDBusPropertyTable *properties, void *user_data, GDBusDestroyFunction destroy); gboolean g_dbus_unregister_interface(DBusConnection *connection, const char *path, const char *name); gboolean g_dbus_register_security(const GDBusSecurityTable *security); gboolean g_dbus_unregister_security(const GDBusSecurityTable *security); void g_dbus_pending_success(DBusConnection *connection, GDBusPendingReply pending); void g_dbus_pending_error(DBusConnection *connection, GDBusPendingReply pending, const char *name, const char *format, ...) __attribute__((format(printf, 4, 5))); void g_dbus_pending_error_valist(DBusConnection *connection, GDBusPendingReply pending, const char *name, const char *format, va_list args); DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name, const char *format, ...) __attribute__((format(printf, 3, 4))); DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name, const char *format, va_list args); DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...); DBusMessage *g_dbus_create_reply_valist(DBusMessage *message, int type, va_list args); gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message); gboolean g_dbus_send_reply(DBusConnection *connection, DBusMessage *message, int type, ...); gboolean g_dbus_send_reply_valist(DBusConnection *connection, DBusMessage *message, int type, va_list args); gboolean g_dbus_emit_signal(DBusConnection *connection, const char *path, const char *interface, const char *name, int type, ...); gboolean g_dbus_emit_signal_valist(DBusConnection *connection, const char *path, const char *interface, const char *name, int type, va_list args); guint g_dbus_add_service_watch(DBusConnection *connection, const char *name, GDBusWatchFunction connect, GDBusWatchFunction disconnect, void *user_data, GDBusDestroyFunction destroy); guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name, GDBusWatchFunction function, void *user_data, GDBusDestroyFunction destroy); guint g_dbus_add_signal_watch(DBusConnection *connection, const char *sender, const char *path, const char *interface, const char *member, GDBusSignalFunction function, void *user_data, GDBusDestroyFunction destroy); gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag); void g_dbus_remove_all_watches(DBusConnection *connection); #ifdef __cplusplus } #endif #endif /* __GDBUS_H */ bluez-4.101/gdbus/object.c0000644000000000000000000004727411766125764012302 00000000000000/* * * D-Bus helper library * * Copyright (C) 2004-2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "gdbus.h" #define info(fmt...) #define error(fmt...) #define debug(fmt...) struct generic_data { unsigned int refcount; GSList *interfaces; char *introspect; }; struct interface_data { char *name; const GDBusMethodTable *methods; const GDBusSignalTable *signals; const GDBusPropertyTable *properties; void *user_data; GDBusDestroyFunction destroy; }; struct security_data { GDBusPendingReply pending; DBusMessage *message; const GDBusMethodTable *method; void *iface_user_data; }; static void print_arguments(GString *gstr, const GDBusArgInfo *args, const char *direction) { for (; args && args->name; args++) { g_string_append_printf(gstr, "\t\t\tname, args->signature); if (direction) g_string_append_printf(gstr, " direction=\"%s\"/>\n", direction); else g_string_append_printf(gstr, "/>\n"); } } static void generate_interface_xml(GString *gstr, struct interface_data *iface) { const GDBusMethodTable *method; const GDBusSignalTable *signal; for (method = iface->methods; method && method->name; method++) { gboolean deprecated = method->flags & G_DBUS_METHOD_FLAG_DEPRECATED; gboolean noreply = method->flags & G_DBUS_METHOD_FLAG_NOREPLY; if (!deprecated && !noreply && !(method->in_args && method->in_args->name) && !(method->out_args && method->out_args->name)) g_string_append_printf(gstr, "\t\t\n", method->name); else { g_string_append_printf(gstr, "\t\t\n", method->name); print_arguments(gstr, method->in_args, "in"); print_arguments(gstr, method->out_args, "out"); if (deprecated) g_string_append_printf(gstr, "\t\t\t\n"); if (noreply) g_string_append_printf(gstr, "\t\t\t\n"); g_string_append_printf(gstr, "\t\t\n"); } } for (signal = iface->signals; signal && signal->name; signal++) { gboolean deprecated = signal->flags & G_DBUS_SIGNAL_FLAG_DEPRECATED; if (!deprecated && !(signal->args && signal->args->name)) g_string_append_printf(gstr, "\t\t\n", signal->name); else { g_string_append_printf(gstr, "\t\t\n", signal->name); print_arguments(gstr, signal->args, NULL); if (deprecated) g_string_append_printf(gstr, "\t\t\t\n"); g_string_append_printf(gstr, "\t\t\n"); } } } static void generate_introspection_xml(DBusConnection *conn, struct generic_data *data, const char *path) { GSList *list; GString *gstr; char **children; int i; g_free(data->introspect); gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE); g_string_append_printf(gstr, "\n"); for (list = data->interfaces; list; list = list->next) { struct interface_data *iface = list->data; g_string_append_printf(gstr, "\t\n", iface->name); generate_interface_xml(gstr, iface); g_string_append_printf(gstr, "\t\n"); } if (!dbus_connection_list_registered(conn, path, &children)) goto done; for (i = 0; children[i]; i++) g_string_append_printf(gstr, "\t\n", children[i]); dbus_free_string_array(children); done: g_string_append_printf(gstr, "\n"); data->introspect = g_string_free(gstr, FALSE); } static DBusMessage *introspect(DBusConnection *connection, DBusMessage *message, void *user_data) { struct generic_data *data = user_data; DBusMessage *reply; if (data->introspect == NULL) generate_introspection_xml(connection, data, dbus_message_get_path(message)); reply = dbus_message_new_method_return(message); if (reply == NULL) return NULL; dbus_message_append_args(reply, DBUS_TYPE_STRING, &data->introspect, DBUS_TYPE_INVALID); return reply; } static DBusHandlerResult process_message(DBusConnection *connection, DBusMessage *message, const GDBusMethodTable *method, void *iface_user_data) { DBusMessage *reply; reply = method->function(connection, message, iface_user_data); if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY) { if (reply != NULL) dbus_message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; } if (method->flags & G_DBUS_METHOD_FLAG_ASYNC) { if (reply == NULL) return DBUS_HANDLER_RESULT_HANDLED; } if (reply == NULL) return DBUS_HANDLER_RESULT_NEED_MEMORY; dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); return DBUS_HANDLER_RESULT_HANDLED; } static GDBusPendingReply next_pending = 1; static GSList *pending_security = NULL; static const GDBusSecurityTable *security_table = NULL; void g_dbus_pending_success(DBusConnection *connection, GDBusPendingReply pending) { GSList *list; for (list = pending_security; list; list = list->next) { struct security_data *secdata = list->data; if (secdata->pending != pending) continue; pending_security = g_slist_remove(pending_security, secdata); process_message(connection, secdata->message, secdata->method, secdata->iface_user_data); dbus_message_unref(secdata->message); g_free(secdata); return; } } void g_dbus_pending_error_valist(DBusConnection *connection, GDBusPendingReply pending, const char *name, const char *format, va_list args) { GSList *list; for (list = pending_security; list; list = list->next) { struct security_data *secdata = list->data; DBusMessage *reply; if (secdata->pending != pending) continue; pending_security = g_slist_remove(pending_security, secdata); reply = g_dbus_create_error_valist(secdata->message, name, format, args); if (reply != NULL) { dbus_connection_send(connection, reply, NULL); dbus_message_unref(reply); } dbus_message_unref(secdata->message); g_free(secdata); return; } } void g_dbus_pending_error(DBusConnection *connection, GDBusPendingReply pending, const char *name, const char *format, ...) { va_list args; va_start(args, format); g_dbus_pending_error_valist(connection, pending, name, format, args); va_end(args); } int polkit_check_authorization(DBusConnection *conn, const char *action, gboolean interaction, void (*function) (dbus_bool_t authorized, void *user_data), void *user_data, int timeout); struct builtin_security_data { DBusConnection *conn; GDBusPendingReply pending; }; static void builtin_security_result(dbus_bool_t authorized, void *user_data) { struct builtin_security_data *data = user_data; if (authorized == TRUE) g_dbus_pending_success(data->conn, data->pending); else g_dbus_pending_error(data->conn, data->pending, DBUS_ERROR_AUTH_FAILED, NULL); g_free(data); } static void builtin_security_function(DBusConnection *conn, const char *action, gboolean interaction, GDBusPendingReply pending) { struct builtin_security_data *data; data = g_new0(struct builtin_security_data, 1); data->conn = conn; data->pending = pending; if (polkit_check_authorization(conn, action, interaction, builtin_security_result, data, 30000) < 0) g_dbus_pending_error(conn, pending, NULL, NULL); } static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg, const GDBusMethodTable *method, void *iface_user_data) { const GDBusSecurityTable *security; for (security = security_table; security && security->privilege; security++) { struct security_data *secdata; gboolean interaction; if (security->privilege != method->privilege) continue; secdata = g_new(struct security_data, 1); secdata->pending = next_pending++; secdata->message = dbus_message_ref(msg); secdata->method = method; secdata->iface_user_data = iface_user_data; pending_security = g_slist_prepend(pending_security, secdata); if (security->flags & G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION) interaction = TRUE; else interaction = FALSE; if (!(security->flags & G_DBUS_SECURITY_FLAG_BUILTIN) && security->function) security->function(conn, security->action, interaction, secdata->pending); else builtin_security_function(conn, security->action, interaction, secdata->pending); return TRUE; } return FALSE; } static void generic_unregister(DBusConnection *connection, void *user_data) { struct generic_data *data = user_data; g_free(data->introspect); g_free(data); } static struct interface_data *find_interface(GSList *interfaces, const char *name) { GSList *list; if (name == NULL) return NULL; for (list = interfaces; list; list = list->next) { struct interface_data *iface = list->data; if (!strcmp(name, iface->name)) return iface; } return NULL; } static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args, DBusMessage *message) { const char *sig = dbus_message_get_signature(message); const char *p = NULL; for (; args && args->signature && *sig; args++) { p = args->signature; for (; *sig && *p; sig++, p++) { if (*p != *sig) return FALSE; } } if (*sig || (p && *p) || (args && args->signature)) return FALSE; return TRUE; } static DBusHandlerResult generic_message(DBusConnection *connection, DBusMessage *message, void *user_data) { struct generic_data *data = user_data; struct interface_data *iface; const GDBusMethodTable *method; const char *interface; interface = dbus_message_get_interface(message); iface = find_interface(data->interfaces, interface); if (iface == NULL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; for (method = iface->methods; method && method->name && method->function; method++) { if (dbus_message_is_method_call(message, iface->name, method->name) == FALSE) continue; if (g_dbus_args_have_signature(method->in_args, message) == FALSE) continue; if (check_privilege(connection, message, method, iface->user_data) == TRUE) return DBUS_HANDLER_RESULT_HANDLED; return process_message(connection, message, method, iface->user_data); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusObjectPathVTable generic_table = { .unregister_function = generic_unregister, .message_function = generic_message, }; static void invalidate_parent_data(DBusConnection *conn, const char *child_path) { struct generic_data *data = NULL; char *parent_path, *slash; parent_path = g_strdup(child_path); slash = strrchr(parent_path, '/'); if (slash == NULL) goto done; if (slash == parent_path && parent_path[1] != '\0') parent_path[1] = '\0'; else *slash = '\0'; if (!strlen(parent_path)) goto done; if (dbus_connection_get_object_path_data(conn, parent_path, (void *) &data) == FALSE) { goto done; } invalidate_parent_data(conn, parent_path); if (data == NULL) goto done; g_free(data->introspect); data->introspect = NULL; done: g_free(parent_path); } static const GDBusMethodTable introspect_methods[] = { { GDBUS_METHOD("Introspect", NULL, GDBUS_ARGS({ "xml", "s" }), introspect) }, { } }; static void add_interface(struct generic_data *data, const char *name, const GDBusMethodTable *methods, const GDBusSignalTable *signals, const GDBusPropertyTable *properties, void *user_data, GDBusDestroyFunction destroy) { struct interface_data *iface; iface = g_new0(struct interface_data, 1); iface->name = g_strdup(name); iface->methods = methods; iface->signals = signals; iface->properties = properties; iface->user_data = user_data; iface->destroy = destroy; data->interfaces = g_slist_append(data->interfaces, iface); } static struct generic_data *object_path_ref(DBusConnection *connection, const char *path) { struct generic_data *data; if (dbus_connection_get_object_path_data(connection, path, (void *) &data) == TRUE) { if (data != NULL) { data->refcount++; return data; } } data = g_new0(struct generic_data, 1); data->refcount = 1; data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE ""); if (!dbus_connection_register_object_path(connection, path, &generic_table, data)) { g_free(data->introspect); g_free(data); return NULL; } invalidate_parent_data(connection, path); add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, introspect_methods, NULL, NULL, data, NULL); return data; } static gboolean remove_interface(struct generic_data *data, const char *name) { struct interface_data *iface; iface = find_interface(data->interfaces, name); if (iface == NULL) return FALSE; data->interfaces = g_slist_remove(data->interfaces, iface); if (iface->destroy) iface->destroy(iface->user_data); g_free(iface->name); g_free(iface); return TRUE; } static void object_path_unref(DBusConnection *connection, const char *path) { struct generic_data *data = NULL; if (dbus_connection_get_object_path_data(connection, path, (void *) &data) == FALSE) return; if (data == NULL) return; data->refcount--; if (data->refcount > 0) return; remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE); invalidate_parent_data(connection, path); dbus_connection_unregister_object_path(connection, path); } static gboolean check_signal(DBusConnection *conn, const char *path, const char *interface, const char *name, const GDBusArgInfo **args) { struct generic_data *data = NULL; struct interface_data *iface; const GDBusSignalTable *signal; *args = NULL; if (!dbus_connection_get_object_path_data(conn, path, (void *) &data) || data == NULL) { error("dbus_connection_emit_signal: path %s isn't registered", path); return FALSE; } iface = find_interface(data->interfaces, interface); if (iface == NULL) { error("dbus_connection_emit_signal: %s does not implement %s", path, interface); return FALSE; } for (signal = iface->signals; signal && signal->name; signal++) { if (!strcmp(signal->name, name)) { *args = signal->args; return TRUE; } } error("No signal named %s on interface %s", name, interface); return FALSE; } static dbus_bool_t emit_signal_valist(DBusConnection *conn, const char *path, const char *interface, const char *name, int first, va_list var_args) { DBusMessage *signal; dbus_bool_t ret; const GDBusArgInfo *args; if (!check_signal(conn, path, interface, name, &args)) return FALSE; signal = dbus_message_new_signal(path, interface, name); if (signal == NULL) { error("Unable to allocate new %s.%s signal", interface, name); return FALSE; } ret = dbus_message_append_args_valist(signal, first, var_args); if (!ret) goto fail; if (g_dbus_args_have_signature(args, signal) == FALSE) { error("%s.%s: expected signature'%s' but got '%s'", interface, name, args, signature); ret = FALSE; goto fail; } ret = dbus_connection_send(conn, signal, NULL); fail: dbus_message_unref(signal); return ret; } gboolean g_dbus_register_interface(DBusConnection *connection, const char *path, const char *name, const GDBusMethodTable *methods, const GDBusSignalTable *signals, const GDBusPropertyTable *properties, void *user_data, GDBusDestroyFunction destroy) { struct generic_data *data; data = object_path_ref(connection, path); if (data == NULL) return FALSE; if (find_interface(data->interfaces, name)) { object_path_unref(connection, path); return FALSE; } add_interface(data, name, methods, signals, properties, user_data, destroy); g_free(data->introspect); data->introspect = NULL; return TRUE; } gboolean g_dbus_unregister_interface(DBusConnection *connection, const char *path, const char *name) { struct generic_data *data = NULL; if (path == NULL) return FALSE; if (dbus_connection_get_object_path_data(connection, path, (void *) &data) == FALSE) return FALSE; if (data == NULL) return FALSE; if (remove_interface(data, name) == FALSE) return FALSE; g_free(data->introspect); data->introspect = NULL; object_path_unref(connection, path); return TRUE; } gboolean g_dbus_register_security(const GDBusSecurityTable *security) { if (security_table != NULL) return FALSE; security_table = security; return TRUE; } gboolean g_dbus_unregister_security(const GDBusSecurityTable *security) { security_table = NULL; return TRUE; } DBusMessage *g_dbus_create_error_valist(DBusMessage *message, const char *name, const char *format, va_list args) { char str[1024]; vsnprintf(str, sizeof(str), format, args); return dbus_message_new_error(message, name, str); } DBusMessage *g_dbus_create_error(DBusMessage *message, const char *name, const char *format, ...) { va_list args; DBusMessage *reply; va_start(args, format); reply = g_dbus_create_error_valist(message, name, format, args); va_end(args); return reply; } DBusMessage *g_dbus_create_reply_valist(DBusMessage *message, int type, va_list args) { DBusMessage *reply; reply = dbus_message_new_method_return(message); if (reply == NULL) return NULL; if (dbus_message_append_args_valist(reply, type, args) == FALSE) { dbus_message_unref(reply); return NULL; } return reply; } DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...) { va_list args; DBusMessage *reply; va_start(args, type); reply = g_dbus_create_reply_valist(message, type, args); va_end(args); return reply; } gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message) { dbus_bool_t result; if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL) dbus_message_set_no_reply(message, TRUE); result = dbus_connection_send(connection, message, NULL); dbus_message_unref(message); return result; } gboolean g_dbus_send_reply_valist(DBusConnection *connection, DBusMessage *message, int type, va_list args) { DBusMessage *reply; reply = dbus_message_new_method_return(message); if (reply == NULL) return FALSE; if (dbus_message_append_args_valist(reply, type, args) == FALSE) { dbus_message_unref(reply); return FALSE; } return g_dbus_send_message(connection, reply); } gboolean g_dbus_send_reply(DBusConnection *connection, DBusMessage *message, int type, ...) { va_list args; gboolean result; va_start(args, type); result = g_dbus_send_reply_valist(connection, message, type, args); va_end(args); return result; } gboolean g_dbus_emit_signal(DBusConnection *connection, const char *path, const char *interface, const char *name, int type, ...) { va_list args; gboolean result; va_start(args, type); result = emit_signal_valist(connection, path, interface, name, type, args); va_end(args); return result; } gboolean g_dbus_emit_signal_valist(DBusConnection *connection, const char *path, const char *interface, const char *name, int type, va_list args) { return emit_signal_valist(connection, path, interface, name, type, args); } bluez-4.101/gdbus/mainloop.c0000644000000000000000000001773611766125764012652 00000000000000/* * * D-Bus helper library * * Copyright (C) 2004-2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include "gdbus.h" #define DISPATCH_TIMEOUT 0 #define info(fmt...) #define error(fmt...) #define debug(fmt...) struct timeout_handler { guint id; DBusTimeout *timeout; }; struct watch_info { guint id; DBusWatch *watch; DBusConnection *conn; }; struct disconnect_data { GDBusWatchFunction function; void *user_data; }; static gboolean disconnected_signal(DBusConnection *conn, DBusMessage *msg, void *data) { struct disconnect_data *dc_data = data; error("Got disconnected from the system message bus"); dc_data->function(conn, dc_data->user_data); dbus_connection_unref(conn); return TRUE; } static gboolean message_dispatch(void *data) { DBusConnection *conn = data; dbus_connection_ref(conn); /* Dispatch messages */ while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS); dbus_connection_unref(conn); return FALSE; } static inline void queue_dispatch(DBusConnection *conn, DBusDispatchStatus status) { if (status == DBUS_DISPATCH_DATA_REMAINS) g_timeout_add(DISPATCH_TIMEOUT, message_dispatch, conn); } static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) { struct watch_info *info = data; unsigned int flags = 0; DBusDispatchStatus status; dbus_connection_ref(info->conn); if (cond & G_IO_IN) flags |= DBUS_WATCH_READABLE; if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE; if (cond & G_IO_HUP) flags |= DBUS_WATCH_HANGUP; if (cond & G_IO_ERR) flags |= DBUS_WATCH_ERROR; dbus_watch_handle(info->watch, flags); status = dbus_connection_get_dispatch_status(info->conn); queue_dispatch(info->conn, status); dbus_connection_unref(info->conn); return TRUE; } static void watch_info_free(void *data) { struct watch_info *info = data; if (info->id > 0) { g_source_remove(info->id); info->id = 0; } dbus_connection_unref(info->conn); g_free(info); } static dbus_bool_t add_watch(DBusWatch *watch, void *data) { DBusConnection *conn = data; GIOCondition cond = G_IO_HUP | G_IO_ERR; GIOChannel *chan; struct watch_info *info; unsigned int flags; int fd; if (!dbus_watch_get_enabled(watch)) return TRUE; info = g_new0(struct watch_info, 1); fd = dbus_watch_get_unix_fd(watch); chan = g_io_channel_unix_new(fd); info->watch = watch; info->conn = dbus_connection_ref(conn); dbus_watch_set_data(watch, info, watch_info_free); flags = dbus_watch_get_flags(watch); if (flags & DBUS_WATCH_READABLE) cond |= G_IO_IN; if (flags & DBUS_WATCH_WRITABLE) cond |= G_IO_OUT; info->id = g_io_add_watch(chan, cond, watch_func, info); g_io_channel_unref(chan); return TRUE; } static void remove_watch(DBusWatch *watch, void *data) { if (dbus_watch_get_enabled(watch)) return; /* will trigger watch_info_free() */ dbus_watch_set_data(watch, NULL, NULL); } static void watch_toggled(DBusWatch *watch, void *data) { /* Because we just exit on OOM, enable/disable is * no different from add/remove */ if (dbus_watch_get_enabled(watch)) add_watch(watch, data); else remove_watch(watch, data); } static gboolean timeout_handler_dispatch(gpointer data) { struct timeout_handler *handler = data; handler->id = 0; /* if not enabled should not be polled by the main loop */ if (!dbus_timeout_get_enabled(handler->timeout)) return FALSE; dbus_timeout_handle(handler->timeout); return FALSE; } static void timeout_handler_free(void *data) { struct timeout_handler *handler = data; if (handler->id > 0) { g_source_remove(handler->id); handler->id = 0; } g_free(handler); } static dbus_bool_t add_timeout(DBusTimeout *timeout, void *data) { int interval = dbus_timeout_get_interval(timeout); struct timeout_handler *handler; if (!dbus_timeout_get_enabled(timeout)) return TRUE; handler = g_new0(struct timeout_handler, 1); handler->timeout = timeout; dbus_timeout_set_data(timeout, handler, timeout_handler_free); handler->id = g_timeout_add(interval, timeout_handler_dispatch, handler); return TRUE; } static void remove_timeout(DBusTimeout *timeout, void *data) { /* will trigger timeout_handler_free() */ dbus_timeout_set_data(timeout, NULL, NULL); } static void timeout_toggled(DBusTimeout *timeout, void *data) { if (dbus_timeout_get_enabled(timeout)) add_timeout(timeout, data); else remove_timeout(timeout, data); } static void dispatch_status(DBusConnection *conn, DBusDispatchStatus status, void *data) { if (!dbus_connection_get_is_connected(conn)) return; queue_dispatch(conn, status); } static inline void setup_dbus_with_main_loop(DBusConnection *conn) { dbus_connection_set_watch_functions(conn, add_watch, remove_watch, watch_toggled, conn, NULL); dbus_connection_set_timeout_functions(conn, add_timeout, remove_timeout, timeout_toggled, NULL, NULL); dbus_connection_set_dispatch_status_function(conn, dispatch_status, NULL, NULL); } static gboolean setup_bus(DBusConnection *conn, const char *name, DBusError *error) { gboolean result; DBusDispatchStatus status; if (name != NULL) { result = g_dbus_request_name(conn, name, error); if (error != NULL) { if (dbus_error_is_set(error) == TRUE) return FALSE; } if (result == FALSE) return FALSE; } setup_dbus_with_main_loop(conn); status = dbus_connection_get_dispatch_status(conn); queue_dispatch(conn, status); return TRUE; } DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name, DBusError *error) { DBusConnection *conn; conn = dbus_bus_get(type, error); if (error != NULL) { if (dbus_error_is_set(error) == TRUE) return NULL; } if (conn == NULL) return NULL; if (setup_bus(conn, name, error) == FALSE) { dbus_connection_unref(conn); return NULL; } return conn; } DBusConnection *g_dbus_setup_private(DBusBusType type, const char *name, DBusError *error) { DBusConnection *conn; conn = dbus_bus_get_private(type, error); if (error != NULL) { if (dbus_error_is_set(error) == TRUE) return NULL; } if (conn == NULL) return NULL; if (setup_bus(conn, name, error) == FALSE) { dbus_connection_unref(conn); return NULL; } return conn; } gboolean g_dbus_request_name(DBusConnection *connection, const char *name, DBusError *error) { int result; result = dbus_bus_request_name(connection, name, DBUS_NAME_FLAG_DO_NOT_QUEUE, error); if (error != NULL) { if (dbus_error_is_set(error) == TRUE) return FALSE; } if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { if (error != NULL) dbus_set_error(error, name, "Name already in use"); return FALSE; } return TRUE; } gboolean g_dbus_set_disconnect_function(DBusConnection *connection, GDBusWatchFunction function, void *user_data, DBusFreeFunction destroy) { struct disconnect_data *dc_data; dc_data = g_new0(struct disconnect_data, 1); dc_data->function = function; dc_data->user_data = user_data; dbus_connection_set_exit_on_disconnect(connection, FALSE); if (g_dbus_add_signal_watch(connection, NULL, NULL, DBUS_INTERFACE_LOCAL, "Disconnected", disconnected_signal, dc_data, g_free) == 0) { error("Failed to add watch for D-Bus Disconnected signal"); g_free(dc_data); return FALSE; } return TRUE; } bluez-4.101/gdbus/watch.c0000644000000000000000000004172311766125764012133 00000000000000/* * * D-Bus helper library * * Copyright (C) 2004-2011 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include "gdbus.h" #define info(fmt...) #define error(fmt...) #define debug(fmt...) static DBusHandlerResult message_filter(DBusConnection *connection, DBusMessage *message, void *user_data); static guint listener_id = 0; static GSList *listeners = NULL; struct service_data { DBusConnection *conn; DBusPendingCall *call; char *name; const char *owner; guint id; struct filter_callback *callback; }; struct filter_callback { GDBusWatchFunction conn_func; GDBusWatchFunction disc_func; GDBusSignalFunction signal_func; GDBusDestroyFunction destroy_func; struct service_data *data; void *user_data; guint id; }; struct filter_data { DBusConnection *connection; DBusHandleMessageFunction handle_func; char *name; char *owner; char *path; char *interface; char *member; char *argument; GSList *callbacks; GSList *processed; guint name_watch; gboolean lock; gboolean registered; }; static struct filter_data *filter_data_find(DBusConnection *connection, const char *name, const char *owner, const char *path, const char *interface, const char *member, const char *argument) { GSList *current; for (current = listeners; current != NULL; current = current->next) { struct filter_data *data = current->data; if (connection != data->connection) continue; if (name && data->name && g_str_equal(name, data->name) == FALSE) continue; if (owner && data->owner && g_str_equal(owner, data->owner) == FALSE) continue; if (path && data->path && g_str_equal(path, data->path) == FALSE) continue; if (interface && data->interface && g_str_equal(interface, data->interface) == FALSE) continue; if (member && data->member && g_str_equal(member, data->member) == FALSE) continue; if (argument && data->argument && g_str_equal(argument, data->argument) == FALSE) continue; return data; } return NULL; } static void format_rule(struct filter_data *data, char *rule, size_t size) { const char *sender; int offset; offset = snprintf(rule, size, "type='signal'"); sender = data->name ? : data->owner; if (sender) offset += snprintf(rule + offset, size - offset, ",sender='%s'", sender); if (data->path) offset += snprintf(rule + offset, size - offset, ",path='%s'", data->path); if (data->interface) offset += snprintf(rule + offset, size - offset, ",interface='%s'", data->interface); if (data->member) offset += snprintf(rule + offset, size - offset, ",member='%s'", data->member); if (data->argument) snprintf(rule + offset, size - offset, ",arg0='%s'", data->argument); } static gboolean add_match(struct filter_data *data, DBusHandleMessageFunction filter) { DBusError err; char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH]; format_rule(data, rule, sizeof(rule)); dbus_error_init(&err); dbus_bus_add_match(data->connection, rule, &err); if (dbus_error_is_set(&err)) { error("Adding match rule \"%s\" failed: %s", rule, err.message); dbus_error_free(&err); return FALSE; } data->handle_func = filter; data->registered = TRUE; return TRUE; } static gboolean remove_match(struct filter_data *data) { DBusError err; char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH]; format_rule(data, rule, sizeof(rule)); dbus_error_init(&err); dbus_bus_remove_match(data->connection, rule, &err); if (dbus_error_is_set(&err)) { error("Removing owner match rule for %s failed: %s", rule, err.message); dbus_error_free(&err); return FALSE; } return TRUE; } static struct filter_data *filter_data_get(DBusConnection *connection, DBusHandleMessageFunction filter, const char *sender, const char *path, const char *interface, const char *member, const char *argument) { struct filter_data *data; const char *name = NULL, *owner = NULL; if (filter_data_find(connection, NULL, NULL, NULL, NULL, NULL, NULL) == NULL) { if (!dbus_connection_add_filter(connection, message_filter, NULL, NULL)) { error("dbus_connection_add_filter() failed"); return NULL; } } if (sender == NULL) goto proceed; if (sender[0] == ':') owner = sender; else name = sender; proceed: data = filter_data_find(connection, name, owner, path, interface, member, argument); if (data) return data; data = g_new0(struct filter_data, 1); data->connection = dbus_connection_ref(connection); data->name = name ? g_strdup(name) : NULL; data->owner = owner ? g_strdup(owner) : NULL; data->path = g_strdup(path); data->interface = g_strdup(interface); data->member = g_strdup(member); data->argument = g_strdup(argument); if (!add_match(data, filter)) { g_free(data); return NULL; } listeners = g_slist_append(listeners, data); return data; } static struct filter_callback *filter_data_find_callback( struct filter_data *data, guint id) { GSList *l; for (l = data->callbacks; l; l = l->next) { struct filter_callback *cb = l->data; if (cb->id == id) return cb; } for (l = data->processed; l; l = l->next) { struct filter_callback *cb = l->data; if (cb->id == id) return cb; } return NULL; } static void filter_data_free(struct filter_data *data) { GSList *l; for (l = data->callbacks; l != NULL; l = l->next) g_free(l->data); g_slist_free(data->callbacks); g_dbus_remove_watch(data->connection, data->name_watch); g_free(data->name); g_free(data->owner); g_free(data->path); g_free(data->interface); g_free(data->member); g_free(data->argument); dbus_connection_unref(data->connection); g_free(data); } static void filter_data_call_and_free(struct filter_data *data) { GSList *l; for (l = data->callbacks; l != NULL; l = l->next) { struct filter_callback *cb = l->data; if (cb->disc_func) cb->disc_func(data->connection, cb->user_data); if (cb->destroy_func) cb->destroy_func(cb->user_data); g_free(cb); } filter_data_free(data); } static struct filter_callback *filter_data_add_callback( struct filter_data *data, GDBusWatchFunction connect, GDBusWatchFunction disconnect, GDBusSignalFunction signal, GDBusDestroyFunction destroy, void *user_data) { struct filter_callback *cb = NULL; cb = g_new0(struct filter_callback, 1); cb->conn_func = connect; cb->disc_func = disconnect; cb->signal_func = signal; cb->destroy_func = destroy; cb->user_data = user_data; cb->id = ++listener_id; if (data->lock) data->processed = g_slist_append(data->processed, cb); else data->callbacks = g_slist_append(data->callbacks, cb); return cb; } static void service_data_free(struct service_data *data) { struct filter_callback *callback = data->callback; dbus_connection_unref(data->conn); if (data->call) dbus_pending_call_unref(data->call); if (data->id) g_source_remove(data->id); g_free(data->name); g_free(data); callback->data = NULL; } static gboolean filter_data_remove_callback(struct filter_data *data, struct filter_callback *cb) { DBusConnection *connection; data->callbacks = g_slist_remove(data->callbacks, cb); data->processed = g_slist_remove(data->processed, cb); /* Cancel pending operations */ if (cb->data) { if (cb->data->call) dbus_pending_call_cancel(cb->data->call); service_data_free(cb->data); } if (cb->destroy_func) cb->destroy_func(cb->user_data); g_free(cb); /* Don't remove the filter if other callbacks exist or data is lock * processing callbacks */ if (data->callbacks || data->lock) return TRUE; if (data->registered && !remove_match(data)) return FALSE; connection = dbus_connection_ref(data->connection); listeners = g_slist_remove(listeners, data); filter_data_free(data); /* Remove filter if there are no listeners left for the connection */ data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL, NULL); if (data == NULL) dbus_connection_remove_filter(connection, message_filter, NULL); dbus_connection_unref(connection); return TRUE; } static DBusHandlerResult signal_filter(DBusConnection *connection, DBusMessage *message, void *user_data) { struct filter_data *data = user_data; struct filter_callback *cb; while (data->callbacks) { cb = data->callbacks->data; if (cb->signal_func && !cb->signal_func(connection, message, cb->user_data)) { filter_data_remove_callback(data, cb); continue; } /* Check if the watch was removed/freed by the callback * function */ if (!g_slist_find(data->callbacks, cb)) continue; data->callbacks = g_slist_remove(data->callbacks, cb); data->processed = g_slist_append(data->processed, cb); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void update_name_cache(const char *name, const char *owner) { GSList *l; for (l = listeners; l != NULL; l = l->next) { struct filter_data *data = l->data; if (g_strcmp0(data->name, name) != 0) continue; g_free(data->owner); data->owner = g_strdup(owner); } } static const char *check_name_cache(const char *name) { GSList *l; for (l = listeners; l != NULL; l = l->next) { struct filter_data *data = l->data; if (g_strcmp0(data->name, name) != 0) continue; return data->owner; } return NULL; } static DBusHandlerResult service_filter(DBusConnection *connection, DBusMessage *message, void *user_data) { struct filter_data *data = user_data; struct filter_callback *cb; char *name, *old, *new; if (!dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old, DBUS_TYPE_STRING, &new, DBUS_TYPE_INVALID)) { error("Invalid arguments for NameOwnerChanged signal"); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } update_name_cache(name, new); while (data->callbacks) { cb = data->callbacks->data; if (*new == '\0') { if (cb->disc_func) cb->disc_func(connection, cb->user_data); } else { if (cb->conn_func) cb->conn_func(connection, cb->user_data); } /* Check if the watch was removed/freed by the callback * function */ if (!g_slist_find(data->callbacks, cb)) continue; /* Only auto remove if it is a bus name watch */ if (data->argument[0] == ':' && (cb->conn_func == NULL || cb->disc_func == NULL)) { filter_data_remove_callback(data, cb); continue; } data->callbacks = g_slist_remove(data->callbacks, cb); data->processed = g_slist_append(data->processed, cb); } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult message_filter(DBusConnection *connection, DBusMessage *message, void *user_data) { struct filter_data *data; const char *sender, *path, *iface, *member, *arg = NULL; /* Only filter signals */ if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; sender = dbus_message_get_sender(message); path = dbus_message_get_path(message); iface = dbus_message_get_interface(message); member = dbus_message_get_member(message); dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); /* Sender is always bus name */ data = filter_data_find(connection, NULL, sender, path, iface, member, arg); if (data == NULL) { error("Got %s.%s signal which has no listeners", iface, member); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } if (data->handle_func) { data->lock = TRUE; data->handle_func(connection, message, data); data->callbacks = data->processed; data->processed = NULL; data->lock = FALSE; } if (data->callbacks) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; remove_match(data); listeners = g_slist_remove(listeners, data); filter_data_free(data); /* Remove filter if there no listener left for the connection */ data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL, NULL); if (data == NULL) dbus_connection_remove_filter(connection, message_filter, NULL); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static gboolean update_service(void *user_data) { struct service_data *data = user_data; struct filter_callback *cb = data->callback; update_name_cache(data->name, data->owner); if (cb->conn_func) cb->conn_func(data->conn, cb->user_data); service_data_free(data); return FALSE; } static void service_reply(DBusPendingCall *call, void *user_data) { struct service_data *data = user_data; DBusMessage *reply; DBusError err; reply = dbus_pending_call_steal_reply(call); if (reply == NULL) return; dbus_error_init(&err); if (dbus_set_error_from_message(&err, reply)) goto fail; if (dbus_message_get_args(reply, &err, DBUS_TYPE_STRING, &data->owner, DBUS_TYPE_INVALID) == FALSE) goto fail; update_service(data); goto done; fail: error("%s", err.message); dbus_error_free(&err); service_data_free(data); done: dbus_message_unref(reply); } static void check_service(DBusConnection *connection, const char *name, struct filter_callback *callback) { DBusMessage *message; struct service_data *data; data = g_try_malloc0(sizeof(*data)); if (data == NULL) { error("Can't allocate data structure"); return; } data->conn = dbus_connection_ref(connection); data->name = g_strdup(name); data->callback = callback; callback->data = data; data->owner = check_name_cache(name); if (data->owner != NULL) { data->id = g_idle_add(update_service, data); return; } message = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner"); if (message == NULL) { error("Can't allocate new message"); g_free(data); return; } dbus_message_append_args(message, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID); if (dbus_connection_send_with_reply(connection, message, &data->call, -1) == FALSE) { error("Failed to execute method call"); g_free(data); goto done; } if (data->call == NULL) { error("D-Bus connection not available"); g_free(data); goto done; } dbus_pending_call_set_notify(data->call, service_reply, data, NULL); done: dbus_message_unref(message); } guint g_dbus_add_service_watch(DBusConnection *connection, const char *name, GDBusWatchFunction connect, GDBusWatchFunction disconnect, void *user_data, GDBusDestroyFunction destroy) { struct filter_data *data; struct filter_callback *cb; if (name == NULL) return 0; data = filter_data_get(connection, service_filter, NULL, NULL, DBUS_INTERFACE_DBUS, "NameOwnerChanged", name); if (data == NULL) return 0; cb = filter_data_add_callback(data, connect, disconnect, NULL, destroy, user_data); if (cb == NULL) return 0; if (connect) check_service(connection, name, cb); return cb->id; } guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name, GDBusWatchFunction func, void *user_data, GDBusDestroyFunction destroy) { return g_dbus_add_service_watch(connection, name, NULL, func, user_data, destroy); } guint g_dbus_add_signal_watch(DBusConnection *connection, const char *sender, const char *path, const char *interface, const char *member, GDBusSignalFunction function, void *user_data, GDBusDestroyFunction destroy) { struct filter_data *data; struct filter_callback *cb; data = filter_data_get(connection, signal_filter, sender, path, interface, member, NULL); if (data == NULL) return 0; cb = filter_data_add_callback(data, NULL, NULL, function, destroy, user_data); if (cb == NULL) return 0; if (data->name != NULL && data->name_watch == 0) data->name_watch = g_dbus_add_service_watch(connection, data->name, NULL, NULL, NULL, NULL); return cb->id; } gboolean g_dbus_remove_watch(DBusConnection *connection, guint id) { struct filter_data *data; struct filter_callback *cb; GSList *ldata; if (id == 0) return FALSE; for (ldata = listeners; ldata; ldata = ldata->next) { data = ldata->data; cb = filter_data_find_callback(data, id); if (cb) { filter_data_remove_callback(data, cb); return TRUE; } } return FALSE; } void g_dbus_remove_all_watches(DBusConnection *connection) { struct filter_data *data; while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL, NULL))) { listeners = g_slist_remove(listeners, data); filter_data_call_and_free(data); } dbus_connection_remove_filter(connection, message_filter, NULL); } bluez-4.101/Makefile.in0000644000000000000000000151036111771117507011612 00000000000000# Makefile.in generated by automake 1.11.3 from Makefile.am. # @configure_input@ # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software # Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \ $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \ $(am__EXEEXT_7) sbin_PROGRAMS = src/bluetoothd$(EXEEXT) $(am__EXEEXT_14) \ $(am__EXEEXT_15) $(am__EXEEXT_16) noinst_PROGRAMS = $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_10) \ $(am__EXEEXT_11) $(am__EXEEXT_13) @SBC_TRUE@am__append_1 = sbc/libsbc.la @SBC_TRUE@am__append_2 = sbc/sbcinfo sbc/sbcdec sbc/sbcenc @SBC_TRUE@@SNDFILE_TRUE@am__append_3 = sbc/sbctester @MCAP_TRUE@am__append_4 = health/mcap_lib.h health/mcap_internal.h \ @MCAP_TRUE@ health/mcap.h health/mcap.c \ @MCAP_TRUE@ health/mcap_sync.c @PNATPLUGIN_TRUE@am__append_5 = pnat @PNATPLUGIN_TRUE@am__append_6 = plugins/pnat.c @AUDIOPLUGIN_TRUE@am__append_7 = audio @AUDIOPLUGIN_TRUE@am__append_8 = audio/main.c \ @AUDIOPLUGIN_TRUE@ audio/manager.h audio/manager.c \ @AUDIOPLUGIN_TRUE@ audio/gateway.h audio/gateway.c \ @AUDIOPLUGIN_TRUE@ audio/headset.h audio/headset.c \ @AUDIOPLUGIN_TRUE@ audio/control.h audio/control.c \ @AUDIOPLUGIN_TRUE@ audio/avctp.h audio/avctp.c \ @AUDIOPLUGIN_TRUE@ audio/avrcp.h audio/avrcp.c \ @AUDIOPLUGIN_TRUE@ audio/device.h audio/device.c \ @AUDIOPLUGIN_TRUE@ audio/source.h audio/source.c \ @AUDIOPLUGIN_TRUE@ audio/sink.h audio/sink.c \ @AUDIOPLUGIN_TRUE@ audio/a2dp.h audio/a2dp.c \ @AUDIOPLUGIN_TRUE@ audio/avdtp.h audio/avdtp.c \ @AUDIOPLUGIN_TRUE@ audio/ipc.h audio/ipc.c \ @AUDIOPLUGIN_TRUE@ audio/unix.h audio/unix.c \ @AUDIOPLUGIN_TRUE@ audio/media.h audio/media.c \ @AUDIOPLUGIN_TRUE@ audio/transport.h audio/transport.c \ @AUDIOPLUGIN_TRUE@ audio/telephony.h audio/a2dp-codecs.h @AUDIOPLUGIN_TRUE@am__append_9 = audio/telephony.c @AUDIOPLUGIN_TRUE@am__append_10 = audio/libtelephony.a @SAPPLUGIN_TRUE@am__append_11 = sap @SAPPLUGIN_TRUE@am__append_12 = sap/main.c \ @SAPPLUGIN_TRUE@ sap/manager.h sap/manager.c \ @SAPPLUGIN_TRUE@ sap/server.h sap/server.c \ @SAPPLUGIN_TRUE@ sap/sap.h @SAPPLUGIN_TRUE@am__append_13 = sap/sap.c @SAPPLUGIN_TRUE@am__append_14 = sap/libsap.a @INPUTPLUGIN_TRUE@am__append_15 = input @INPUTPLUGIN_TRUE@am__append_16 = input/main.c \ @INPUTPLUGIN_TRUE@ input/manager.h input/manager.c \ @INPUTPLUGIN_TRUE@ input/server.h input/server.c \ @INPUTPLUGIN_TRUE@ input/device.h input/device.c \ @INPUTPLUGIN_TRUE@ input/fakehid.c input/fakehid.h @SERIALPLUGIN_TRUE@am__append_17 = serial @SERIALPLUGIN_TRUE@am__append_18 = serial/main.c \ @SERIALPLUGIN_TRUE@ serial/manager.h serial/manager.c \ @SERIALPLUGIN_TRUE@ serial/proxy.h serial/proxy.c \ @SERIALPLUGIN_TRUE@ serial/port.h serial/port.c @NETWORKPLUGIN_TRUE@am__append_19 = network @NETWORKPLUGIN_TRUE@am__append_20 = network/main.c \ @NETWORKPLUGIN_TRUE@ network/manager.h network/manager.c \ @NETWORKPLUGIN_TRUE@ network/common.h network/common.c \ @NETWORKPLUGIN_TRUE@ network/server.h network/server.c \ @NETWORKPLUGIN_TRUE@ network/connection.h network/connection.c @SERVICEPLUGIN_TRUE@am__append_21 = service @SERVICEPLUGIN_TRUE@am__append_22 = plugins/service.c @HEALTHPLUGIN_TRUE@am__append_23 = health @HEALTHPLUGIN_TRUE@am__append_24 = health/hdp_main.c health/hdp_types.h \ @HEALTHPLUGIN_TRUE@ health/hdp_manager.h health/hdp_manager.c \ @HEALTHPLUGIN_TRUE@ health/hdp.h health/hdp.c \ @HEALTHPLUGIN_TRUE@ health/hdp_util.h health/hdp_util.c @GATTMODULES_TRUE@am__append_25 = thermometer alert time gatt_example proximity \ @GATTMODULES_TRUE@ deviceinfo @GATTMODULES_TRUE@am__append_26 = thermometer/main.c \ @GATTMODULES_TRUE@ thermometer/manager.h thermometer/manager.c \ @GATTMODULES_TRUE@ thermometer/thermometer.h thermometer/thermometer.c \ @GATTMODULES_TRUE@ alert/main.c alert/server.h alert/server.c \ @GATTMODULES_TRUE@ time/main.c time/server.h time/server.c \ @GATTMODULES_TRUE@ plugins/gatt-example.c \ @GATTMODULES_TRUE@ proximity/main.c proximity/manager.h proximity/manager.c \ @GATTMODULES_TRUE@ proximity/monitor.h proximity/monitor.c \ @GATTMODULES_TRUE@ proximity/reporter.h proximity/reporter.c \ @GATTMODULES_TRUE@ proximity/linkloss.h proximity/linkloss.c \ @GATTMODULES_TRUE@ proximity/immalert.h proximity/immalert.c \ @GATTMODULES_TRUE@ deviceinfo/main.c \ @GATTMODULES_TRUE@ deviceinfo/manager.h deviceinfo/manager.c \ @GATTMODULES_TRUE@ deviceinfo/deviceinfo.h deviceinfo/deviceinfo.c @HAL_TRUE@am__append_27 = hal @HAL_TRUE@am__append_28 = plugins/hal.c @HAL_FALSE@am__append_29 = formfactor @HAL_FALSE@am__append_30 = plugins/formfactor.c @WIIMOTEPLUGIN_TRUE@am__append_31 = wiimote @WIIMOTEPLUGIN_TRUE@am__append_32 = plugins/wiimote.c @MAEMO6PLUGIN_TRUE@am__append_33 = maemo6 @MAEMO6PLUGIN_TRUE@am__append_34 = plugins/maemo6.c @DBUSOOBPLUGIN_TRUE@am__append_35 = dbusoob @DBUSOOBPLUGIN_TRUE@am__append_36 = plugins/dbusoob.c @MAINTAINER_MODE_TRUE@am__append_37 = plugins/external-dummy.la DIST_COMMON = README $(am__configure_deps) \ $(am__dist_udev_SCRIPTS_DIST) $(dist_man_MANS) \ $(include_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ $(srcdir)/Makefile.tools $(srcdir)/bluez.pc.in \ $(srcdir)/config.h.in $(top_srcdir)/configure \ $(top_srcdir)/doc/version.xml.in \ $(top_srcdir)/src/bluetooth.service.in \ $(top_srcdir)/src/bluetoothd.8.in AUTHORS COPYING COPYING.LIB \ ChangeLog INSTALL NEWS TODO compile config.guess config.sub \ depcomp install-sh ltmain.sh missing tools/lexer.c \ tools/parser.c tools/parser.h ylwrap @DATAFILES_TRUE@@TOOLS_TRUE@am__append_38 = tools/rfcomm.conf @TOOLS_TRUE@am__append_39 = tools/rfcomm tools/l2ping \ @TOOLS_TRUE@ tools/hcitool tools/sdptool tools/ciptool @TOOLS_TRUE@am__append_40 = tools/hciattach tools/hciconfig @TOOLS_TRUE@am__append_41 = tools/avinfo tools/ppporc \ @TOOLS_TRUE@ tools/hcieventmask tools/hcisecfilter mgmt/btmgmt \ @TOOLS_TRUE@ monitor/btmon emulator/btvirt @READLINE_TRUE@@TOOLS_TRUE@am__append_42 = attrib/gatttool @TOOLS_TRUE@am__append_43 = tools/rfcomm.1 tools/l2ping.8 \ @TOOLS_TRUE@ tools/hciattach.8 tools/hciconfig.8 \ @TOOLS_TRUE@ tools/hcitool.1 tools/sdptool.1 tools/ciptool.1 @TOOLS_FALSE@am__append_44 = tools/rfcomm.1 tools/l2ping.8 \ @TOOLS_FALSE@ tools/hciattach.8 tools/hciconfig.8 \ @TOOLS_FALSE@ tools/hcitool.1 tools/sdptool.1 tools/ciptool.1 @BCCMD_TRUE@am__append_45 = tools/bccmd @BCCMD_TRUE@@USB_TRUE@am__append_46 = tools/csr_usb.c @BCCMD_TRUE@@USB_TRUE@am__append_47 = @USB_LIBS@ @BCCMD_TRUE@am__append_48 = tools/bccmd.8 @BCCMD_FALSE@am__append_49 = tools/bccmd.8 @HID2HCI_TRUE@udev_PROGRAMS = tools/hid2hci$(EXEEXT) @HID2HCI_TRUE@am__append_50 = tools/hid2hci.8 @HID2HCI_FALSE@am__append_51 = tools/hid2hci.8 @DFUTOOL_TRUE@am__append_52 = tools/dfutool @DFUTOOL_TRUE@am__append_53 = tools/dfutool.1 @DFUTOOL_FALSE@am__append_54 = tools/dfutool.1 @USB_TRUE@am__append_55 = tools/dfubabel tools/avctrl @CUPS_TRUE@cups_PROGRAMS = cups/bluetooth$(EXEEXT) @TEST_TRUE@am__append_56 = test/hciemu @TEST_TRUE@am__append_57 = test/l2test test/rctest @TEST_TRUE@am__append_58 = test/gaptest test/sdptest test/scotest \ @TEST_TRUE@ test/attest test/hstest test/avtest test/ipctest \ @TEST_TRUE@ test/lmptest test/bdaddr test/agent test/btiotest \ @TEST_TRUE@ test/test-textfile test/uuidtest test/mpris-player \ @TEST_TRUE@ $(unit_tests) @TEST_TRUE@am__append_59 = test/rctest.1 test/hciemu.1 @TEST_TRUE@am__append_60 = test/bdaddr.8 @TEST_FALSE@am__append_61 = test/rctest.1 test/hciemu.1 test/bdaddr.8 @HIDD_TRUE@am__append_62 = compat/hidd @HIDD_TRUE@am__append_63 = compat/hidd.1 @HIDD_FALSE@am__append_64 = compat/hidd.1 @PAND_TRUE@am__append_65 = compat/pand @PAND_TRUE@am__append_66 = compat/pand.1 @PAND_FALSE@am__append_67 = compat/pand.1 @DUND_TRUE@am__append_68 = compat/dund @DUND_TRUE@am__append_69 = compat/dund.1 @DUND_FALSE@am__append_70 = compat/dund.1 @DATAFILES_TRUE@@HID2HCI_TRUE@am__append_71 = scripts/bluetooth-hid2hci.rules @DATAFILES_TRUE@@PCMCIA_TRUE@am__append_72 = scripts/bluetooth-serial.rules @MCAP_TRUE@am__append_73 = -I$(builddir)/health @TEST_TRUE@am__append_74 = $(unit_test_eir_OBJECTS) TESTS = $(am__EXEEXT_12) subdir = . ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \ $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = config.h CONFIG_CLEAN_FILES = doc/version.xml src/bluetoothd.8 \ src/bluetooth.service bluez.pc CONFIG_CLEAN_VPATH_FILES = LIBRARIES = $(noinst_LIBRARIES) ARFLAGS = cru AM_V_AR = $(am__v_AR_@AM_V@) am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) am__v_AR_0 = @echo " AR " $@; AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ audio_libtelephony_a_AR = $(AR) $(ARFLAGS) audio_libtelephony_a_LIBADD = am__audio_libtelephony_a_SOURCES_DIST = audio/telephony.h \ audio/telephony-dummy.c audio/telephony-maemo5.c \ audio/telephony-ofono.c audio/telephony-maemo6.c am__dirstamp = $(am__leading_dot)dirstamp @AUDIOPLUGIN_TRUE@am_audio_libtelephony_a_OBJECTS = \ @AUDIOPLUGIN_TRUE@ audio/telephony-dummy.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/telephony-maemo5.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/telephony-ofono.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/telephony-maemo6.$(OBJEXT) audio_libtelephony_a_OBJECTS = $(am_audio_libtelephony_a_OBJECTS) sap_libsap_a_AR = $(AR) $(ARFLAGS) sap_libsap_a_LIBADD = am__sap_libsap_a_SOURCES_DIST = sap/sap.h sap/sap-dummy.c \ sap/sap-u8500.c @SAPPLUGIN_TRUE@am_sap_libsap_a_OBJECTS = sap/sap-dummy.$(OBJEXT) \ @SAPPLUGIN_TRUE@ sap/sap-u8500.$(OBJEXT) sap_libsap_a_OBJECTS = $(am_sap_libsap_a_OBJECTS) am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } am__installdirs = "$(DESTDIR)$(alsadir)" "$(DESTDIR)$(gstreamerdir)" \ "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cupsdir)" \ "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(udevdir)" \ "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(man1dir)" \ "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(alsaconfdir)" \ "$(DESTDIR)$(confdir)" "$(DESTDIR)$(dbusdir)" \ "$(DESTDIR)$(dbusservicedir)" "$(DESTDIR)$(pkgconfigdir)" \ "$(DESTDIR)$(rulesdir)" "$(DESTDIR)$(statedir)" \ "$(DESTDIR)$(systemdunitdir)" "$(DESTDIR)$(includedir)" LTLIBRARIES = $(alsa_LTLIBRARIES) $(gstreamer_LTLIBRARIES) \ $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES) @ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_DEPENDENCIES = \ @ALSA_TRUE@ lib/libbluetooth-private.la am__audio_libasound_module_ctl_bluetooth_la_SOURCES_DIST = \ audio/ctl_bluetooth.c audio/rtp.h audio/ipc.h audio/ipc.c @ALSA_TRUE@am_audio_libasound_module_ctl_bluetooth_la_OBJECTS = audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo \ @ALSA_TRUE@ audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo audio_libasound_module_ctl_bluetooth_la_OBJECTS = \ $(am_audio_libasound_module_ctl_bluetooth_la_OBJECTS) AM_V_lt = $(am__v_lt_@AM_V@) am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) am__v_lt_0 = --silent audio_libasound_module_ctl_bluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) \ $(CFLAGS) $(audio_libasound_module_ctl_bluetooth_la_LDFLAGS) \ $(LDFLAGS) -o $@ @ALSA_TRUE@am_audio_libasound_module_ctl_bluetooth_la_rpath = -rpath \ @ALSA_TRUE@ $(alsadir) @ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_DEPENDENCIES = \ @ALSA_TRUE@ sbc/libsbc.la lib/libbluetooth-private.la am__audio_libasound_module_pcm_bluetooth_la_SOURCES_DIST = \ audio/pcm_bluetooth.c audio/rtp.h audio/ipc.h audio/ipc.c @ALSA_TRUE@am_audio_libasound_module_pcm_bluetooth_la_OBJECTS = audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo \ @ALSA_TRUE@ audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo audio_libasound_module_pcm_bluetooth_la_OBJECTS = \ $(am_audio_libasound_module_pcm_bluetooth_la_OBJECTS) audio_libasound_module_pcm_bluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) \ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ $(CCLD) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) \ $(CFLAGS) $(audio_libasound_module_pcm_bluetooth_la_LDFLAGS) \ $(LDFLAGS) -o $@ @ALSA_TRUE@am_audio_libasound_module_pcm_bluetooth_la_rpath = -rpath \ @ALSA_TRUE@ $(alsadir) @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_DEPENDENCIES = \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ sbc/libsbc.la \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ lib/libbluetooth-private.la am__audio_libgstbluetooth_la_SOURCES_DIST = audio/gstbluetooth.c \ audio/gstpragma.h audio/gstsbcenc.h audio/gstsbcenc.c \ audio/gstsbcdec.h audio/gstsbcdec.c audio/gstsbcparse.h \ audio/gstsbcparse.c audio/gstavdtpsink.h audio/gstavdtpsink.c \ audio/gsta2dpsink.h audio/gsta2dpsink.c audio/gstsbcutil.h \ audio/gstsbcutil.c audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \ audio/rtp.h audio/ipc.h audio/ipc.c @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@am_audio_libgstbluetooth_la_OBJECTS = audio/audio_libgstbluetooth_la-gstbluetooth.lo \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/audio_libgstbluetooth_la-gstsbcenc.lo \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/audio_libgstbluetooth_la-gstsbcdec.lo \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/audio_libgstbluetooth_la-gstsbcparse.lo \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/audio_libgstbluetooth_la-gstavdtpsink.lo \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/audio_libgstbluetooth_la-gsta2dpsink.lo \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/audio_libgstbluetooth_la-gstsbcutil.lo \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/audio_libgstbluetooth_la-ipc.lo audio_libgstbluetooth_la_OBJECTS = \ $(am_audio_libgstbluetooth_la_OBJECTS) audio_libgstbluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) \ $(audio_libgstbluetooth_la_LDFLAGS) $(LDFLAGS) -o $@ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@am_audio_libgstbluetooth_la_rpath = \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ -rpath $(gstreamerdir) lib_libbluetooth_private_la_LIBADD = am__objects_1 = am__objects_2 = $(am__objects_1) lib/bluetooth.lo lib/hci.lo \ lib/sdp.lo lib/uuid.lo am_lib_libbluetooth_private_la_OBJECTS = $(am__objects_2) lib_libbluetooth_private_la_OBJECTS = \ $(am_lib_libbluetooth_private_la_OBJECTS) lib_libbluetooth_la_LIBADD = am_lib_libbluetooth_la_OBJECTS = $(am__objects_1) lib/bluetooth.lo \ lib/hci.lo lib/sdp.lo lib/uuid.lo lib_libbluetooth_la_OBJECTS = $(am_lib_libbluetooth_la_OBJECTS) lib_libbluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(AM_CFLAGS) $(CFLAGS) $(lib_libbluetooth_la_LDFLAGS) \ $(LDFLAGS) -o $@ plugins_external_dummy_la_LIBADD = am__plugins_external_dummy_la_SOURCES_DIST = plugins/external-dummy.c @MAINTAINER_MODE_TRUE@am_plugins_external_dummy_la_OBJECTS = plugins/plugins_external_dummy_la-external-dummy.lo plugins_external_dummy_la_OBJECTS = \ $(am_plugins_external_dummy_la_OBJECTS) plugins_external_dummy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) \ $(plugins_external_dummy_la_LDFLAGS) $(LDFLAGS) -o $@ @MAINTAINER_MODE_TRUE@am_plugins_external_dummy_la_rpath = -rpath \ @MAINTAINER_MODE_TRUE@ $(plugindir) sbc_libsbc_la_LIBADD = am__sbc_libsbc_la_SOURCES_DIST = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h \ sbc/sbc_tables.h sbc/sbc_primitives.h sbc/sbc_primitives.c \ sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \ sbc/sbc_primitives_iwmmxt.h sbc/sbc_primitives_iwmmxt.c \ sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \ sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c @SBC_TRUE@am_sbc_libsbc_la_OBJECTS = sbc/sbc_libsbc_la-sbc.lo \ @SBC_TRUE@ sbc/sbc_libsbc_la-sbc_primitives.lo \ @SBC_TRUE@ sbc/sbc_libsbc_la-sbc_primitives_mmx.lo \ @SBC_TRUE@ sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo \ @SBC_TRUE@ sbc/sbc_libsbc_la-sbc_primitives_neon.lo \ @SBC_TRUE@ sbc/sbc_libsbc_la-sbc_primitives_armv6.lo sbc_libsbc_la_OBJECTS = $(am_sbc_libsbc_la_OBJECTS) sbc_libsbc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(sbc_libsbc_la_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ @SBC_TRUE@am_sbc_libsbc_la_rpath = @TOOLS_TRUE@am__EXEEXT_1 = tools/rfcomm$(EXEEXT) tools/l2ping$(EXEEXT) \ @TOOLS_TRUE@ tools/hcitool$(EXEEXT) tools/sdptool$(EXEEXT) \ @TOOLS_TRUE@ tools/ciptool$(EXEEXT) @READLINE_TRUE@@TOOLS_TRUE@am__EXEEXT_2 = attrib/gatttool$(EXEEXT) @DFUTOOL_TRUE@am__EXEEXT_3 = tools/dfutool$(EXEEXT) @TEST_TRUE@am__EXEEXT_4 = test/l2test$(EXEEXT) test/rctest$(EXEEXT) @HIDD_TRUE@am__EXEEXT_5 = compat/hidd$(EXEEXT) @PAND_TRUE@am__EXEEXT_6 = compat/pand$(EXEEXT) @DUND_TRUE@am__EXEEXT_7 = compat/dund$(EXEEXT) @SBC_TRUE@am__EXEEXT_8 = sbc/sbcinfo$(EXEEXT) sbc/sbcdec$(EXEEXT) \ @SBC_TRUE@ sbc/sbcenc$(EXEEXT) @SBC_TRUE@@SNDFILE_TRUE@am__EXEEXT_9 = sbc/sbctester$(EXEEXT) @TOOLS_TRUE@am__EXEEXT_10 = tools/avinfo$(EXEEXT) \ @TOOLS_TRUE@ tools/ppporc$(EXEEXT) tools/hcieventmask$(EXEEXT) \ @TOOLS_TRUE@ tools/hcisecfilter$(EXEEXT) mgmt/btmgmt$(EXEEXT) \ @TOOLS_TRUE@ monitor/btmon$(EXEEXT) emulator/btvirt$(EXEEXT) @USB_TRUE@am__EXEEXT_11 = tools/dfubabel$(EXEEXT) \ @USB_TRUE@ tools/avctrl$(EXEEXT) @TEST_TRUE@am__EXEEXT_12 = unit/test-eir$(EXEEXT) @TEST_TRUE@am__EXEEXT_13 = test/gaptest$(EXEEXT) test/sdptest$(EXEEXT) \ @TEST_TRUE@ test/scotest$(EXEEXT) test/attest$(EXEEXT) \ @TEST_TRUE@ test/hstest$(EXEEXT) test/avtest$(EXEEXT) \ @TEST_TRUE@ test/ipctest$(EXEEXT) test/lmptest$(EXEEXT) \ @TEST_TRUE@ test/bdaddr$(EXEEXT) test/agent$(EXEEXT) \ @TEST_TRUE@ test/btiotest$(EXEEXT) test/test-textfile$(EXEEXT) \ @TEST_TRUE@ test/uuidtest$(EXEEXT) test/mpris-player$(EXEEXT) \ @TEST_TRUE@ $(am__EXEEXT_12) @TOOLS_TRUE@am__EXEEXT_14 = tools/hciattach$(EXEEXT) \ @TOOLS_TRUE@ tools/hciconfig$(EXEEXT) @BCCMD_TRUE@am__EXEEXT_15 = tools/bccmd$(EXEEXT) @TEST_TRUE@am__EXEEXT_16 = test/hciemu$(EXEEXT) PROGRAMS = $(bin_PROGRAMS) $(cups_PROGRAMS) $(noinst_PROGRAMS) \ $(sbin_PROGRAMS) $(udev_PROGRAMS) am__attrib_gatttool_SOURCES_DIST = attrib/gatttool.c attrib/att.c \ attrib/gatt.c attrib/gattrib.c btio/btio.c attrib/gatttool.h \ attrib/interactive.c attrib/utils.c src/log.c @READLINE_TRUE@@TOOLS_TRUE@am_attrib_gatttool_OBJECTS = \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/gatttool.$(OBJEXT) \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/att.$(OBJEXT) \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/gatt.$(OBJEXT) \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/gattrib.$(OBJEXT) \ @READLINE_TRUE@@TOOLS_TRUE@ btio/btio.$(OBJEXT) \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/interactive.$(OBJEXT) \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/utils.$(OBJEXT) \ @READLINE_TRUE@@TOOLS_TRUE@ src/log.$(OBJEXT) attrib_gatttool_OBJECTS = $(am_attrib_gatttool_OBJECTS) @READLINE_TRUE@@TOOLS_TRUE@attrib_gatttool_DEPENDENCIES = \ @READLINE_TRUE@@TOOLS_TRUE@ lib/libbluetooth-private.la am__compat_dund_SOURCES_DIST = compat/dund.c compat/dund.h \ compat/lib.h compat/sdp.h compat/sdp.c compat/dun.c \ compat/msdun.c src/textfile.h src/textfile.c @DUND_TRUE@am_compat_dund_OBJECTS = compat/dund.$(OBJEXT) \ @DUND_TRUE@ compat/sdp.$(OBJEXT) compat/dun.$(OBJEXT) \ @DUND_TRUE@ compat/msdun.$(OBJEXT) src/textfile.$(OBJEXT) compat_dund_OBJECTS = $(am_compat_dund_OBJECTS) @DUND_TRUE@compat_dund_DEPENDENCIES = lib/libbluetooth-private.la am__compat_hidd_SOURCES_DIST = compat/hidd.c compat/hidd.h \ src/uinput.h compat/sdp.h compat/sdp.c compat/fakehid.c \ src/textfile.h src/textfile.c @HIDD_TRUE@am_compat_hidd_OBJECTS = compat/hidd.$(OBJEXT) \ @HIDD_TRUE@ compat/sdp.$(OBJEXT) compat/fakehid.$(OBJEXT) \ @HIDD_TRUE@ src/textfile.$(OBJEXT) compat_hidd_OBJECTS = $(am_compat_hidd_OBJECTS) @HIDD_TRUE@compat_hidd_DEPENDENCIES = lib/libbluetooth-private.la am__compat_pand_SOURCES_DIST = compat/pand.c compat/pand.h \ compat/bnep.c compat/sdp.h compat/sdp.c src/textfile.h \ src/textfile.c @PAND_TRUE@am_compat_pand_OBJECTS = compat/pand.$(OBJEXT) \ @PAND_TRUE@ compat/bnep.$(OBJEXT) compat/sdp.$(OBJEXT) \ @PAND_TRUE@ src/textfile.$(OBJEXT) compat_pand_OBJECTS = $(am_compat_pand_OBJECTS) @PAND_TRUE@compat_pand_DEPENDENCIES = lib/libbluetooth-private.la am__cups_bluetooth_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \ gdbus/watch.c gdbus/object.c gdbus/polkit.c cups/main.c \ cups/cups.h cups/sdp.c cups/spp.c cups/hcrp.c am__objects_3 = gdbus/mainloop.$(OBJEXT) gdbus/watch.$(OBJEXT) \ gdbus/object.$(OBJEXT) gdbus/polkit.$(OBJEXT) @CUPS_TRUE@am_cups_bluetooth_OBJECTS = $(am__objects_3) \ @CUPS_TRUE@ cups/main.$(OBJEXT) cups/sdp.$(OBJEXT) \ @CUPS_TRUE@ cups/spp.$(OBJEXT) cups/hcrp.$(OBJEXT) cups_bluetooth_OBJECTS = $(am_cups_bluetooth_OBJECTS) @CUPS_TRUE@cups_bluetooth_DEPENDENCIES = lib/libbluetooth-private.la am__emulator_btvirt_SOURCES_DIST = emulator/main.c monitor/bt.h \ monitor/mainloop.h monitor/mainloop.c emulator/server.h \ emulator/server.c emulator/vhci.h emulator/vhci.c \ emulator/btdev.h emulator/btdev.c @TOOLS_TRUE@am_emulator_btvirt_OBJECTS = emulator/main.$(OBJEXT) \ @TOOLS_TRUE@ monitor/mainloop.$(OBJEXT) \ @TOOLS_TRUE@ emulator/server.$(OBJEXT) emulator/vhci.$(OBJEXT) \ @TOOLS_TRUE@ emulator/btdev.$(OBJEXT) emulator_btvirt_OBJECTS = $(am_emulator_btvirt_OBJECTS) emulator_btvirt_LDADD = $(LDADD) am__mgmt_btmgmt_SOURCES_DIST = mgmt/main.c src/glib-helper.c @TOOLS_TRUE@am_mgmt_btmgmt_OBJECTS = mgmt/main.$(OBJEXT) \ @TOOLS_TRUE@ src/glib-helper.$(OBJEXT) mgmt_btmgmt_OBJECTS = $(am_mgmt_btmgmt_OBJECTS) @TOOLS_TRUE@mgmt_btmgmt_DEPENDENCIES = lib/libbluetooth-private.la am__monitor_btmon_SOURCES_DIST = monitor/main.c monitor/bt.h \ monitor/mainloop.h monitor/mainloop.c monitor/hcidump.h \ monitor/hcidump.c monitor/btsnoop.h monitor/btsnoop.c \ monitor/control.h monitor/control.c monitor/packet.h \ monitor/packet.c @TOOLS_TRUE@am_monitor_btmon_OBJECTS = monitor/main.$(OBJEXT) \ @TOOLS_TRUE@ monitor/mainloop.$(OBJEXT) \ @TOOLS_TRUE@ monitor/hcidump.$(OBJEXT) \ @TOOLS_TRUE@ monitor/btsnoop.$(OBJEXT) \ @TOOLS_TRUE@ monitor/control.$(OBJEXT) monitor/packet.$(OBJEXT) monitor_btmon_OBJECTS = $(am_monitor_btmon_OBJECTS) @TOOLS_TRUE@monitor_btmon_DEPENDENCIES = lib/libbluetooth-private.la am__sbc_sbcdec_SOURCES_DIST = sbc/sbcdec.c sbc/formats.h @SBC_TRUE@am_sbc_sbcdec_OBJECTS = sbc/sbcdec.$(OBJEXT) sbc_sbcdec_OBJECTS = $(am_sbc_sbcdec_OBJECTS) @SBC_TRUE@sbc_sbcdec_DEPENDENCIES = sbc/libsbc.la am__sbc_sbcenc_SOURCES_DIST = sbc/sbcenc.c sbc/formats.h @SBC_TRUE@am_sbc_sbcenc_OBJECTS = sbc/sbcenc.$(OBJEXT) sbc_sbcenc_OBJECTS = $(am_sbc_sbcenc_OBJECTS) @SBC_TRUE@sbc_sbcenc_DEPENDENCIES = sbc/libsbc.la sbc_sbcinfo_SOURCES = sbc/sbcinfo.c sbc_sbcinfo_OBJECTS = sbc/sbcinfo.$(OBJEXT) sbc_sbcinfo_LDADD = $(LDADD) sbc_sbctester_SOURCES = sbc/sbctester.c sbc_sbctester_OBJECTS = sbc/sbctester.$(OBJEXT) sbc_sbctester_DEPENDENCIES = am__src_bluetoothd_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \ gdbus/watch.c gdbus/object.c gdbus/polkit.c plugins/pnat.c \ audio/main.c audio/manager.h audio/manager.c audio/gateway.h \ audio/gateway.c audio/headset.h audio/headset.c \ audio/control.h audio/control.c audio/avctp.h audio/avctp.c \ audio/avrcp.h audio/avrcp.c audio/device.h audio/device.c \ audio/source.h audio/source.c audio/sink.h audio/sink.c \ audio/a2dp.h audio/a2dp.c audio/avdtp.h audio/avdtp.c \ audio/ipc.h audio/ipc.c audio/unix.h audio/unix.c \ audio/media.h audio/media.c audio/transport.h \ audio/transport.c audio/telephony.h audio/a2dp-codecs.h \ sap/main.c sap/manager.h sap/manager.c sap/server.h \ sap/server.c sap/sap.h input/main.c input/manager.h \ input/manager.c input/server.h input/server.c input/device.h \ input/device.c input/fakehid.c input/fakehid.h serial/main.c \ serial/manager.h serial/manager.c serial/proxy.h \ serial/proxy.c serial/port.h serial/port.c network/main.c \ network/manager.h network/manager.c network/common.h \ network/common.c network/server.h network/server.c \ network/connection.h network/connection.c plugins/service.c \ health/hdp_main.c health/hdp_types.h health/hdp_manager.h \ health/hdp_manager.c health/hdp.h health/hdp.c \ health/hdp_util.h health/hdp_util.c thermometer/main.c \ thermometer/manager.h thermometer/manager.c \ thermometer/thermometer.h thermometer/thermometer.c \ alert/main.c alert/server.h alert/server.c time/main.c \ time/server.h time/server.c plugins/gatt-example.c \ proximity/main.c proximity/manager.h proximity/manager.c \ proximity/monitor.h proximity/monitor.c proximity/reporter.h \ proximity/reporter.c proximity/linkloss.h proximity/linkloss.c \ proximity/immalert.h proximity/immalert.c deviceinfo/main.c \ deviceinfo/manager.h deviceinfo/manager.c \ deviceinfo/deviceinfo.h deviceinfo/deviceinfo.c \ plugins/hciops.c plugins/mgmtops.c plugins/hal.c \ plugins/formfactor.c plugins/storage.c plugins/adaptername.c \ plugins/wiimote.c plugins/maemo6.c plugins/dbusoob.c \ attrib/att.h attrib/att-database.h attrib/att.c attrib/gatt.h \ attrib/gatt.c attrib/gattrib.h attrib/gattrib.c \ attrib/client.h attrib/client.c attrib/gatt-service.h \ attrib/gatt-service.c btio/btio.h btio/btio.c \ health/mcap_lib.h health/mcap_internal.h health/mcap.h \ health/mcap.c health/mcap_sync.c src/bluetooth.ver src/main.c \ src/log.h src/log.c src/rfkill.c src/hcid.h src/sdpd.h \ src/sdpd-server.c src/sdpd-request.c src/sdpd-service.c \ src/sdpd-database.c src/attrib-server.h src/attrib-server.c \ src/sdp-xml.h src/sdp-xml.c src/sdp-client.h src/sdp-client.c \ src/textfile.h src/textfile.c src/glib-helper.h \ src/glib-helper.c src/oui.h src/oui.c src/uinput.h src/ppoll.h \ src/plugin.h src/plugin.c src/storage.h src/storage.c \ src/agent.h src/agent.c src/error.h src/error.c src/manager.h \ src/manager.c src/adapter.h src/adapter.c src/device.h \ src/device.c src/attio.h src/dbus-common.c src/dbus-common.h \ src/event.h src/event.c src/oob.h src/oob.c src/eir.h \ src/eir.c am__objects_4 = gdbus/bluetoothd-mainloop.$(OBJEXT) \ gdbus/bluetoothd-watch.$(OBJEXT) \ gdbus/bluetoothd-object.$(OBJEXT) \ gdbus/bluetoothd-polkit.$(OBJEXT) @PNATPLUGIN_TRUE@am__objects_5 = plugins/bluetoothd-pnat.$(OBJEXT) @AUDIOPLUGIN_TRUE@am__objects_6 = audio/bluetoothd-main.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-manager.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-gateway.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-headset.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-control.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-avctp.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-avrcp.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-device.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-source.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-sink.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-a2dp.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-avdtp.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-ipc.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-unix.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-media.$(OBJEXT) \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-transport.$(OBJEXT) @SAPPLUGIN_TRUE@am__objects_7 = sap/bluetoothd-main.$(OBJEXT) \ @SAPPLUGIN_TRUE@ sap/bluetoothd-manager.$(OBJEXT) \ @SAPPLUGIN_TRUE@ sap/bluetoothd-server.$(OBJEXT) @INPUTPLUGIN_TRUE@am__objects_8 = input/bluetoothd-main.$(OBJEXT) \ @INPUTPLUGIN_TRUE@ input/bluetoothd-manager.$(OBJEXT) \ @INPUTPLUGIN_TRUE@ input/bluetoothd-server.$(OBJEXT) \ @INPUTPLUGIN_TRUE@ input/bluetoothd-device.$(OBJEXT) \ @INPUTPLUGIN_TRUE@ input/bluetoothd-fakehid.$(OBJEXT) @SERIALPLUGIN_TRUE@am__objects_9 = serial/bluetoothd-main.$(OBJEXT) \ @SERIALPLUGIN_TRUE@ serial/bluetoothd-manager.$(OBJEXT) \ @SERIALPLUGIN_TRUE@ serial/bluetoothd-proxy.$(OBJEXT) \ @SERIALPLUGIN_TRUE@ serial/bluetoothd-port.$(OBJEXT) @NETWORKPLUGIN_TRUE@am__objects_10 = \ @NETWORKPLUGIN_TRUE@ network/bluetoothd-main.$(OBJEXT) \ @NETWORKPLUGIN_TRUE@ network/bluetoothd-manager.$(OBJEXT) \ @NETWORKPLUGIN_TRUE@ network/bluetoothd-common.$(OBJEXT) \ @NETWORKPLUGIN_TRUE@ network/bluetoothd-server.$(OBJEXT) \ @NETWORKPLUGIN_TRUE@ network/bluetoothd-connection.$(OBJEXT) @SERVICEPLUGIN_TRUE@am__objects_11 = \ @SERVICEPLUGIN_TRUE@ plugins/bluetoothd-service.$(OBJEXT) @HEALTHPLUGIN_TRUE@am__objects_12 = \ @HEALTHPLUGIN_TRUE@ health/bluetoothd-hdp_main.$(OBJEXT) \ @HEALTHPLUGIN_TRUE@ health/bluetoothd-hdp_manager.$(OBJEXT) \ @HEALTHPLUGIN_TRUE@ health/bluetoothd-hdp.$(OBJEXT) \ @HEALTHPLUGIN_TRUE@ health/bluetoothd-hdp_util.$(OBJEXT) @GATTMODULES_TRUE@am__objects_13 = \ @GATTMODULES_TRUE@ thermometer/bluetoothd-main.$(OBJEXT) \ @GATTMODULES_TRUE@ thermometer/bluetoothd-manager.$(OBJEXT) \ @GATTMODULES_TRUE@ thermometer/bluetoothd-thermometer.$(OBJEXT) \ @GATTMODULES_TRUE@ alert/bluetoothd-main.$(OBJEXT) \ @GATTMODULES_TRUE@ alert/bluetoothd-server.$(OBJEXT) \ @GATTMODULES_TRUE@ time/bluetoothd-main.$(OBJEXT) \ @GATTMODULES_TRUE@ time/bluetoothd-server.$(OBJEXT) \ @GATTMODULES_TRUE@ plugins/bluetoothd-gatt-example.$(OBJEXT) \ @GATTMODULES_TRUE@ proximity/bluetoothd-main.$(OBJEXT) \ @GATTMODULES_TRUE@ proximity/bluetoothd-manager.$(OBJEXT) \ @GATTMODULES_TRUE@ proximity/bluetoothd-monitor.$(OBJEXT) \ @GATTMODULES_TRUE@ proximity/bluetoothd-reporter.$(OBJEXT) \ @GATTMODULES_TRUE@ proximity/bluetoothd-linkloss.$(OBJEXT) \ @GATTMODULES_TRUE@ proximity/bluetoothd-immalert.$(OBJEXT) \ @GATTMODULES_TRUE@ deviceinfo/bluetoothd-main.$(OBJEXT) \ @GATTMODULES_TRUE@ deviceinfo/bluetoothd-manager.$(OBJEXT) \ @GATTMODULES_TRUE@ deviceinfo/bluetoothd-deviceinfo.$(OBJEXT) @HAL_TRUE@am__objects_14 = plugins/bluetoothd-hal.$(OBJEXT) @HAL_FALSE@am__objects_15 = plugins/bluetoothd-formfactor.$(OBJEXT) @WIIMOTEPLUGIN_TRUE@am__objects_16 = \ @WIIMOTEPLUGIN_TRUE@ plugins/bluetoothd-wiimote.$(OBJEXT) @MAEMO6PLUGIN_TRUE@am__objects_17 = \ @MAEMO6PLUGIN_TRUE@ plugins/bluetoothd-maemo6.$(OBJEXT) @DBUSOOBPLUGIN_TRUE@am__objects_18 = \ @DBUSOOBPLUGIN_TRUE@ plugins/bluetoothd-dbusoob.$(OBJEXT) am__objects_19 = $(am__objects_5) $(am__objects_6) $(am__objects_7) \ $(am__objects_8) $(am__objects_9) $(am__objects_10) \ $(am__objects_11) $(am__objects_12) $(am__objects_13) \ plugins/bluetoothd-hciops.$(OBJEXT) \ plugins/bluetoothd-mgmtops.$(OBJEXT) $(am__objects_14) \ $(am__objects_15) plugins/bluetoothd-storage.$(OBJEXT) \ plugins/bluetoothd-adaptername.$(OBJEXT) $(am__objects_16) \ $(am__objects_17) $(am__objects_18) am__objects_20 = attrib/bluetoothd-att.$(OBJEXT) \ attrib/bluetoothd-gatt.$(OBJEXT) \ attrib/bluetoothd-gattrib.$(OBJEXT) \ attrib/bluetoothd-client.$(OBJEXT) \ attrib/bluetoothd-gatt-service.$(OBJEXT) am__objects_21 = btio/bluetoothd-btio.$(OBJEXT) @MCAP_TRUE@am__objects_22 = health/bluetoothd-mcap.$(OBJEXT) \ @MCAP_TRUE@ health/bluetoothd-mcap_sync.$(OBJEXT) am__objects_23 = $(am__objects_22) am_src_bluetoothd_OBJECTS = $(am__objects_4) $(am__objects_19) \ $(am__objects_20) $(am__objects_21) $(am__objects_23) \ src/bluetoothd-main.$(OBJEXT) src/bluetoothd-log.$(OBJEXT) \ src/bluetoothd-rfkill.$(OBJEXT) \ src/bluetoothd-sdpd-server.$(OBJEXT) \ src/bluetoothd-sdpd-request.$(OBJEXT) \ src/bluetoothd-sdpd-service.$(OBJEXT) \ src/bluetoothd-sdpd-database.$(OBJEXT) \ src/bluetoothd-attrib-server.$(OBJEXT) \ src/bluetoothd-sdp-xml.$(OBJEXT) \ src/bluetoothd-sdp-client.$(OBJEXT) \ src/bluetoothd-textfile.$(OBJEXT) \ src/bluetoothd-glib-helper.$(OBJEXT) \ src/bluetoothd-oui.$(OBJEXT) src/bluetoothd-plugin.$(OBJEXT) \ src/bluetoothd-storage.$(OBJEXT) \ src/bluetoothd-agent.$(OBJEXT) src/bluetoothd-error.$(OBJEXT) \ src/bluetoothd-manager.$(OBJEXT) \ src/bluetoothd-adapter.$(OBJEXT) \ src/bluetoothd-device.$(OBJEXT) \ src/bluetoothd-dbus-common.$(OBJEXT) \ src/bluetoothd-event.$(OBJEXT) src/bluetoothd-oob.$(OBJEXT) \ src/bluetoothd-eir.$(OBJEXT) @AUDIOPLUGIN_TRUE@am__objects_24 = \ @AUDIOPLUGIN_TRUE@ audio/bluetoothd-telephony.$(OBJEXT) @SAPPLUGIN_TRUE@am__objects_25 = sap/bluetoothd-sap.$(OBJEXT) am__objects_26 = $(am__objects_24) $(am__objects_25) am__objects_27 = $(am__objects_26) nodist_src_bluetoothd_OBJECTS = $(am__objects_27) src_bluetoothd_OBJECTS = $(am_src_bluetoothd_OBJECTS) \ $(nodist_src_bluetoothd_OBJECTS) src_bluetoothd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ $(src_bluetoothd_CFLAGS) $(CFLAGS) $(src_bluetoothd_LDFLAGS) \ $(LDFLAGS) -o $@ test_agent_SOURCES = test/agent.c test_agent_OBJECTS = test/agent.$(OBJEXT) test_agent_DEPENDENCIES = test_attest_SOURCES = test/attest.c test_attest_OBJECTS = test/attest.$(OBJEXT) @TEST_TRUE@test_attest_DEPENDENCIES = lib/libbluetooth-private.la test_avtest_SOURCES = test/avtest.c test_avtest_OBJECTS = test/avtest.$(OBJEXT) @TEST_TRUE@test_avtest_DEPENDENCIES = lib/libbluetooth-private.la am__test_bdaddr_SOURCES_DIST = test/bdaddr.c src/oui.h src/oui.c @TEST_TRUE@am_test_bdaddr_OBJECTS = test/bdaddr.$(OBJEXT) \ @TEST_TRUE@ src/oui.$(OBJEXT) test_bdaddr_OBJECTS = $(am_test_bdaddr_OBJECTS) @TEST_TRUE@test_bdaddr_DEPENDENCIES = lib/libbluetooth-private.la am__test_btiotest_SOURCES_DIST = test/btiotest.c btio/btio.h \ btio/btio.c @TEST_TRUE@am_test_btiotest_OBJECTS = test/btiotest.$(OBJEXT) \ @TEST_TRUE@ btio/btio.$(OBJEXT) test_btiotest_OBJECTS = $(am_test_btiotest_OBJECTS) @TEST_TRUE@test_btiotest_DEPENDENCIES = lib/libbluetooth-private.la test_gaptest_SOURCES = test/gaptest.c test_gaptest_OBJECTS = test/gaptest.$(OBJEXT) test_gaptest_DEPENDENCIES = test_hciemu_SOURCES = test/hciemu.c test_hciemu_OBJECTS = test/hciemu.$(OBJEXT) @TEST_TRUE@test_hciemu_DEPENDENCIES = lib/libbluetooth-private.la test_hstest_SOURCES = test/hstest.c test_hstest_OBJECTS = test/hstest.$(OBJEXT) @TEST_TRUE@test_hstest_DEPENDENCIES = lib/libbluetooth-private.la am__test_ipctest_SOURCES_DIST = test/ipctest.c audio/ipc.h audio/ipc.c @TEST_TRUE@am_test_ipctest_OBJECTS = test/ipctest.$(OBJEXT) \ @TEST_TRUE@ audio/ipc.$(OBJEXT) test_ipctest_OBJECTS = $(am_test_ipctest_OBJECTS) @TEST_TRUE@test_ipctest_DEPENDENCIES = sbc/libsbc.la test_l2test_SOURCES = test/l2test.c test_l2test_OBJECTS = test/l2test.$(OBJEXT) @TEST_TRUE@test_l2test_DEPENDENCIES = lib/libbluetooth-private.la test_lmptest_SOURCES = test/lmptest.c test_lmptest_OBJECTS = test/lmptest.$(OBJEXT) @TEST_TRUE@test_lmptest_DEPENDENCIES = lib/libbluetooth-private.la am__test_mpris_player_SOURCES_DIST = test/mpris-player.c @TEST_TRUE@am_test_mpris_player_OBJECTS = test/mpris-player.$(OBJEXT) test_mpris_player_OBJECTS = $(am_test_mpris_player_OBJECTS) test_mpris_player_DEPENDENCIES = test_rctest_SOURCES = test/rctest.c test_rctest_OBJECTS = test/rctest.$(OBJEXT) @TEST_TRUE@test_rctest_DEPENDENCIES = lib/libbluetooth-private.la test_scotest_SOURCES = test/scotest.c test_scotest_OBJECTS = test/scotest.$(OBJEXT) @TEST_TRUE@test_scotest_DEPENDENCIES = lib/libbluetooth-private.la test_sdptest_SOURCES = test/sdptest.c test_sdptest_OBJECTS = test/sdptest.$(OBJEXT) @TEST_TRUE@test_sdptest_DEPENDENCIES = lib/libbluetooth-private.la am__test_test_textfile_SOURCES_DIST = test/test-textfile.c \ src/textfile.h src/textfile.c @TEST_TRUE@am_test_test_textfile_OBJECTS = \ @TEST_TRUE@ test/test-textfile.$(OBJEXT) src/textfile.$(OBJEXT) test_test_textfile_OBJECTS = $(am_test_test_textfile_OBJECTS) test_test_textfile_LDADD = $(LDADD) am__test_uuidtest_SOURCES_DIST = test/uuidtest.c @TEST_TRUE@am_test_uuidtest_OBJECTS = test/uuidtest.$(OBJEXT) test_uuidtest_OBJECTS = $(am_test_uuidtest_OBJECTS) @TEST_TRUE@test_uuidtest_DEPENDENCIES = lib/libbluetooth-private.la tools_avctrl_SOURCES = tools/avctrl.c tools_avctrl_OBJECTS = tools/avctrl.$(OBJEXT) tools_avctrl_DEPENDENCIES = tools_avinfo_SOURCES = tools/avinfo.c tools_avinfo_OBJECTS = tools/avinfo.$(OBJEXT) @TOOLS_TRUE@tools_avinfo_DEPENDENCIES = lib/libbluetooth-private.la am__tools_bccmd_SOURCES_DIST = tools/bccmd.c tools/csr.h tools/csr.c \ tools/csr_hci.c tools/csr_h4.c tools/csr_3wire.c \ tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c tools/csr_usb.c @BCCMD_TRUE@@USB_TRUE@am__objects_28 = tools/csr_usb.$(OBJEXT) @BCCMD_TRUE@am_tools_bccmd_OBJECTS = tools/bccmd.$(OBJEXT) \ @BCCMD_TRUE@ tools/csr.$(OBJEXT) tools/csr_hci.$(OBJEXT) \ @BCCMD_TRUE@ tools/csr_h4.$(OBJEXT) tools/csr_3wire.$(OBJEXT) \ @BCCMD_TRUE@ tools/csr_bcsp.$(OBJEXT) tools/ubcsp.$(OBJEXT) \ @BCCMD_TRUE@ $(am__objects_28) tools_bccmd_OBJECTS = $(am_tools_bccmd_OBJECTS) am__DEPENDENCIES_1 = @BCCMD_TRUE@tools_bccmd_DEPENDENCIES = lib/libbluetooth-private.la \ @BCCMD_TRUE@ $(am__DEPENDENCIES_1) tools_ciptool_SOURCES = tools/ciptool.c tools_ciptool_OBJECTS = tools/ciptool.$(OBJEXT) @TOOLS_TRUE@tools_ciptool_DEPENDENCIES = lib/libbluetooth-private.la tools_dfubabel_SOURCES = tools/dfubabel.c tools_dfubabel_OBJECTS = tools/dfubabel.$(OBJEXT) tools_dfubabel_DEPENDENCIES = am__tools_dfutool_SOURCES_DIST = tools/dfutool.c tools/dfu.h \ tools/dfu.c @DFUTOOL_TRUE@am_tools_dfutool_OBJECTS = tools/dfutool.$(OBJEXT) \ @DFUTOOL_TRUE@ tools/dfu.$(OBJEXT) tools_dfutool_OBJECTS = $(am_tools_dfutool_OBJECTS) tools_dfutool_DEPENDENCIES = am__tools_hciattach_SOURCES_DIST = tools/hciattach.c tools/hciattach.h \ tools/hciattach_st.c tools/hciattach_ti.c \ tools/hciattach_tialt.c tools/hciattach_ath3k.c \ tools/hciattach_qualcomm.c tools/hciattach_intel.c @TOOLS_TRUE@am_tools_hciattach_OBJECTS = tools/hciattach.$(OBJEXT) \ @TOOLS_TRUE@ tools/hciattach_st.$(OBJEXT) \ @TOOLS_TRUE@ tools/hciattach_ti.$(OBJEXT) \ @TOOLS_TRUE@ tools/hciattach_tialt.$(OBJEXT) \ @TOOLS_TRUE@ tools/hciattach_ath3k.$(OBJEXT) \ @TOOLS_TRUE@ tools/hciattach_qualcomm.$(OBJEXT) \ @TOOLS_TRUE@ tools/hciattach_intel.$(OBJEXT) tools_hciattach_OBJECTS = $(am_tools_hciattach_OBJECTS) @TOOLS_TRUE@tools_hciattach_DEPENDENCIES = \ @TOOLS_TRUE@ lib/libbluetooth-private.la am__tools_hciconfig_SOURCES_DIST = tools/hciconfig.c tools/csr.h \ tools/csr.c src/textfile.h src/textfile.c @TOOLS_TRUE@am_tools_hciconfig_OBJECTS = tools/hciconfig.$(OBJEXT) \ @TOOLS_TRUE@ tools/csr.$(OBJEXT) src/textfile.$(OBJEXT) tools_hciconfig_OBJECTS = $(am_tools_hciconfig_OBJECTS) @TOOLS_TRUE@tools_hciconfig_DEPENDENCIES = \ @TOOLS_TRUE@ lib/libbluetooth-private.la tools_hcieventmask_SOURCES = tools/hcieventmask.c tools_hcieventmask_OBJECTS = tools/hcieventmask.$(OBJEXT) @TOOLS_TRUE@tools_hcieventmask_DEPENDENCIES = \ @TOOLS_TRUE@ lib/libbluetooth-private.la tools_hcisecfilter_SOURCES = tools/hcisecfilter.c tools_hcisecfilter_OBJECTS = tools/hcisecfilter.$(OBJEXT) tools_hcisecfilter_LDADD = $(LDADD) am__tools_hcitool_SOURCES_DIST = tools/hcitool.c src/oui.h src/oui.c \ src/textfile.h src/textfile.c @TOOLS_TRUE@am_tools_hcitool_OBJECTS = tools/hcitool.$(OBJEXT) \ @TOOLS_TRUE@ src/oui.$(OBJEXT) src/textfile.$(OBJEXT) tools_hcitool_OBJECTS = $(am_tools_hcitool_OBJECTS) @TOOLS_TRUE@tools_hcitool_DEPENDENCIES = lib/libbluetooth-private.la tools_hid2hci_SOURCES = tools/hid2hci.c tools_hid2hci_OBJECTS = tools/hid2hci.$(OBJEXT) tools_hid2hci_DEPENDENCIES = tools_l2ping_SOURCES = tools/l2ping.c tools_l2ping_OBJECTS = tools/l2ping.$(OBJEXT) @TOOLS_TRUE@tools_l2ping_DEPENDENCIES = lib/libbluetooth-private.la tools_ppporc_SOURCES = tools/ppporc.c tools_ppporc_OBJECTS = tools/ppporc.$(OBJEXT) @TOOLS_TRUE@tools_ppporc_DEPENDENCIES = lib/libbluetooth-private.la am__tools_rfcomm_SOURCES_DIST = tools/rfcomm.c tools/parser.y \ tools/lexer.l tools/kword.h tools/kword.c @TOOLS_TRUE@am_tools_rfcomm_OBJECTS = tools/rfcomm.$(OBJEXT) \ @TOOLS_TRUE@ tools/parser.$(OBJEXT) tools/lexer.$(OBJEXT) \ @TOOLS_TRUE@ tools/kword.$(OBJEXT) am__EXTRA_tools_rfcomm_SOURCES_DIST = tools/parser.h tools/parser.c \ tools/lexer.c tools_rfcomm_OBJECTS = $(am_tools_rfcomm_OBJECTS) @TOOLS_TRUE@tools_rfcomm_DEPENDENCIES = lib/libbluetooth-private.la am__tools_sdptool_SOURCES_DIST = tools/sdptool.c src/sdp-xml.h \ src/sdp-xml.c @TOOLS_TRUE@am_tools_sdptool_OBJECTS = tools/sdptool.$(OBJEXT) \ @TOOLS_TRUE@ src/sdp-xml.$(OBJEXT) tools_sdptool_OBJECTS = $(am_tools_sdptool_OBJECTS) @TOOLS_TRUE@tools_sdptool_DEPENDENCIES = lib/libbluetooth-private.la am__unit_test_eir_SOURCES_DIST = unit/test-eir.c src/eir.c \ src/glib-helper.c @TEST_TRUE@am_unit_test_eir_OBJECTS = \ @TEST_TRUE@ unit/unit_test_eir-test-eir.$(OBJEXT) \ @TEST_TRUE@ src/unit_test_eir-eir.$(OBJEXT) \ @TEST_TRUE@ src/unit_test_eir-glib-helper.$(OBJEXT) unit_test_eir_OBJECTS = $(am_unit_test_eir_OBJECTS) @TEST_TRUE@unit_test_eir_DEPENDENCIES = lib/libbluetooth-private.la unit_test_eir_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(unit_test_eir_CFLAGS) \ $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ am__dist_udev_SCRIPTS_DIST = scripts/bluetooth_serial SCRIPTS = $(dist_udev_SCRIPTS) DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; CCLD = $(CC) LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; @MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ || LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS) LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS) AM_V_LEX = $(am__v_LEX_@AM_V@) am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@) am__v_LEX_0 = @echo " LEX " $@; YLWRAP = $(top_srcdir)/ylwrap @MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ || YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS) LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \ $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS) AM_V_YACC = $(am__v_YACC_@AM_V@) am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@) am__v_YACC_0 = @echo " YACC " $@; AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; SOURCES = $(audio_libtelephony_a_SOURCES) $(sap_libsap_a_SOURCES) \ $(audio_libasound_module_ctl_bluetooth_la_SOURCES) \ $(audio_libasound_module_pcm_bluetooth_la_SOURCES) \ $(audio_libgstbluetooth_la_SOURCES) \ $(lib_libbluetooth_private_la_SOURCES) \ $(lib_libbluetooth_la_SOURCES) \ $(plugins_external_dummy_la_SOURCES) $(sbc_libsbc_la_SOURCES) \ $(attrib_gatttool_SOURCES) $(compat_dund_SOURCES) \ $(compat_hidd_SOURCES) $(compat_pand_SOURCES) \ $(cups_bluetooth_SOURCES) $(emulator_btvirt_SOURCES) \ $(mgmt_btmgmt_SOURCES) $(monitor_btmon_SOURCES) \ $(sbc_sbcdec_SOURCES) $(sbc_sbcenc_SOURCES) sbc/sbcinfo.c \ sbc/sbctester.c $(src_bluetoothd_SOURCES) \ $(nodist_src_bluetoothd_SOURCES) test/agent.c test/attest.c \ test/avtest.c $(test_bdaddr_SOURCES) $(test_btiotest_SOURCES) \ test/gaptest.c test/hciemu.c test/hstest.c \ $(test_ipctest_SOURCES) test/l2test.c test/lmptest.c \ $(test_mpris_player_SOURCES) test/rctest.c test/scotest.c \ test/sdptest.c $(test_test_textfile_SOURCES) \ $(test_uuidtest_SOURCES) tools/avctrl.c tools/avinfo.c \ $(tools_bccmd_SOURCES) tools/ciptool.c tools/dfubabel.c \ $(tools_dfutool_SOURCES) $(tools_hciattach_SOURCES) \ $(tools_hciconfig_SOURCES) tools/hcieventmask.c \ tools/hcisecfilter.c $(tools_hcitool_SOURCES) tools/hid2hci.c \ tools/l2ping.c tools/ppporc.c $(tools_rfcomm_SOURCES) \ $(EXTRA_tools_rfcomm_SOURCES) $(tools_sdptool_SOURCES) \ $(unit_test_eir_SOURCES) DIST_SOURCES = $(am__audio_libtelephony_a_SOURCES_DIST) \ $(am__sap_libsap_a_SOURCES_DIST) \ $(am__audio_libasound_module_ctl_bluetooth_la_SOURCES_DIST) \ $(am__audio_libasound_module_pcm_bluetooth_la_SOURCES_DIST) \ $(am__audio_libgstbluetooth_la_SOURCES_DIST) \ $(lib_libbluetooth_private_la_SOURCES) \ $(lib_libbluetooth_la_SOURCES) \ $(am__plugins_external_dummy_la_SOURCES_DIST) \ $(am__sbc_libsbc_la_SOURCES_DIST) \ $(am__attrib_gatttool_SOURCES_DIST) \ $(am__compat_dund_SOURCES_DIST) \ $(am__compat_hidd_SOURCES_DIST) \ $(am__compat_pand_SOURCES_DIST) \ $(am__cups_bluetooth_SOURCES_DIST) \ $(am__emulator_btvirt_SOURCES_DIST) \ $(am__mgmt_btmgmt_SOURCES_DIST) \ $(am__monitor_btmon_SOURCES_DIST) \ $(am__sbc_sbcdec_SOURCES_DIST) $(am__sbc_sbcenc_SOURCES_DIST) \ sbc/sbcinfo.c sbc/sbctester.c \ $(am__src_bluetoothd_SOURCES_DIST) test/agent.c test/attest.c \ test/avtest.c $(am__test_bdaddr_SOURCES_DIST) \ $(am__test_btiotest_SOURCES_DIST) test/gaptest.c test/hciemu.c \ test/hstest.c $(am__test_ipctest_SOURCES_DIST) test/l2test.c \ test/lmptest.c $(am__test_mpris_player_SOURCES_DIST) \ test/rctest.c test/scotest.c test/sdptest.c \ $(am__test_test_textfile_SOURCES_DIST) \ $(am__test_uuidtest_SOURCES_DIST) tools/avctrl.c \ tools/avinfo.c $(am__tools_bccmd_SOURCES_DIST) tools/ciptool.c \ tools/dfubabel.c $(am__tools_dfutool_SOURCES_DIST) \ $(am__tools_hciattach_SOURCES_DIST) \ $(am__tools_hciconfig_SOURCES_DIST) tools/hcieventmask.c \ tools/hcisecfilter.c $(am__tools_hcitool_SOURCES_DIST) \ tools/hid2hci.c tools/l2ping.c tools/ppporc.c \ $(am__tools_rfcomm_SOURCES_DIST) \ $(am__EXTRA_tools_rfcomm_SOURCES_DIST) \ $(am__tools_sdptool_SOURCES_DIST) \ $(am__unit_test_eir_SOURCES_DIST) man1dir = $(mandir)/man1 man8dir = $(mandir)/man8 NROFF = nroff MANS = $(dist_man_MANS) $(man_MANS) DATA = $(alsaconf_DATA) $(conf_DATA) $(dbus_DATA) $(dbusservice_DATA) \ $(pkgconfig_DATA) $(rules_DATA) $(state_DATA) \ $(systemdunit_DATA) HEADERS = $(include_HEADERS) ETAGS = etags CTAGS = ctags # If stdout is a non-dumb tty, use colors. If test -t is not supported, # then this fails; a conservative approach. Of course do not redirect # stdout here, just stderr. am__tty_colors = \ red=; grn=; lgn=; blu=; std=; \ test "X$(AM_COLOR_TESTS)" != Xno \ && test "X$$TERM" != Xdumb \ && { test "X$(AM_COLOR_TESTS)" = Xalways || test -t 1 2>/dev/null; } \ && { \ red=''; \ grn=''; \ lgn=''; \ blu=''; \ std=''; \ } DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ ALSA_CFLAGS = @ALSA_CFLAGS@ ALSA_LIBS = @ALSA_LIBS@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AR = @AR@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CHECK_CFLAGS = @CHECK_CFLAGS@ CHECK_LIBS = @CHECK_LIBS@ CONFIGDIR = @CONFIGDIR@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DBUS_CFLAGS = @DBUS_CFLAGS@ DBUS_LIBS = @DBUS_LIBS@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ GLIB_CFLAGS = @GLIB_CFLAGS@ GLIB_LIBS = @GLIB_LIBS@ GREP = @GREP@ GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@ GSTREAMER_LIBS = @GSTREAMER_LIBS@ GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LD = @LD@ LDFLAGS = @LDFLAGS@ LEX = @LEX@ LEXLIB = @LEXLIB@ LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LIBTOOL = @LIBTOOL@ LIPO = @LIPO@ LN_S = @LN_S@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ MISC_CFLAGS = @MISC_CFLAGS@ MISC_LDFLAGS = @MISC_LDFLAGS@ MKDIR_P = @MKDIR_P@ NM = @NM@ NMEDIT = @NMEDIT@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ OTOOL64 = @OTOOL64@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ RANLIB = @RANLIB@ READLINE_LIBS = @READLINE_LIBS@ SAP_DRIVER = @SAP_DRIVER@ SED = @SED@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ SNDFILE_CFLAGS = @SNDFILE_CFLAGS@ SNDFILE_LIBS = @SNDFILE_LIBS@ STORAGEDIR = @STORAGEDIR@ STRIP = @STRIP@ SYSTEMD_UNITDIR = @SYSTEMD_UNITDIR@ TELEPHONY_DRIVER = @TELEPHONY_DRIVER@ UDEV_CFLAGS = @UDEV_CFLAGS@ UDEV_DIR = @UDEV_DIR@ UDEV_LIBS = @UDEV_LIBS@ USB_CFLAGS = @USB_CFLAGS@ USB_LIBS = @USB_LIBS@ VERSION = @VERSION@ WARNING_CFLAGS = @WARNING_CFLAGS@ YACC = @YACC@ YFLAGS = @YFLAGS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_AR = @ac_ct_AR@ ac_ct_CC = @ac_ct_CC@ ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@/bluetooth infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ AM_MAKEFLAGS = --no-print-directory lib_LTLIBRARIES = lib/libbluetooth.la noinst_LIBRARIES = $(am__append_10) $(am__append_14) noinst_LTLIBRARIES = lib/libbluetooth-private.la $(am__append_1) dist_man_MANS = $(am__append_43) $(am__append_48) $(am__append_50) \ $(am__append_53) $(am__append_59) $(am__append_63) \ $(am__append_66) $(am__append_69) dist_noinst_MANS = CLEANFILES = $(builtin_files) tools/lexer.c tools/parser.c \ tools/parser.h $(rules_DATA) EXTRA_DIST = plugins/hal.c plugins/formfactor.c src/genbuiltin \ src/bluetooth.conf src/org.bluez.service src/main.conf \ network/network.conf input/input.conf serial/serial.conf \ audio/audio.conf audio/telephony-dummy.c \ audio/telephony-maemo5.c audio/telephony-ofono.c \ audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c \ proximity/proximity.conf audio/bluetooth.conf $(am__append_44) \ tools/rfcomm.conf $(am__append_49) $(am__append_51) \ $(am__append_54) tools/dfubabel.1 tools/avctrl.8 \ $(am__append_60) $(am__append_61) test/sap-client test/hsplay \ test/hsmicro test/dbusdef.py test/monitor-bluetooth \ test/list-devices test/test-discovery test/test-manager \ test/test-adapter test/test-device test/test-service \ test/test-serial test/test-telephony test/test-network \ test/simple-agent test/simple-service test/simple-endpoint \ test/test-audio test/test-input test/test-sap-server \ test/test-oob test/test-attrib test/test-proximity \ test/test-thermometer test/test-serial-proxy test/test-health \ test/test-health-sink test/service-record.dtd \ test/service-did.xml test/service-spp.xml test/service-opp.xml \ test/service-ftp.xml test/simple-player test/test-nap \ $(am__append_64) $(am__append_67) $(am__append_70) \ scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules \ doc/manager-api.txt doc/adapter-api.txt doc/device-api.txt \ doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \ doc/serial-api.txt doc/network-api.txt doc/input-api.txt \ doc/audio-api.txt doc/control-api.txt doc/hfp-api.txt \ doc/health-api.txt doc/sap-api.txt doc/media-api.txt \ doc/assigned-numbers.txt include_HEADERS = $(lib_headers) AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS) @DBUS_CFLAGS@ \ @GLIB_CFLAGS@ $(am__empty) AM_LDFLAGS = $(MISC_LDFLAGS) @DATAFILES_TRUE@dbusdir = $(sysconfdir)/dbus-1/system.d @DATAFILES_TRUE@dbusservicedir = $(datadir)/dbus-1/system-services @DATAFILES_TRUE@dbus_DATA = src/bluetooth.conf @DATAFILES_TRUE@dbusservice_DATA = src/org.bluez.service @DATAFILES_TRUE@confdir = $(sysconfdir)/bluetooth @DATAFILES_TRUE@conf_DATA = src/main.conf $(am__append_38) @DATAFILES_TRUE@statedir = $(localstatedir)/lib/bluetooth @DATAFILES_TRUE@state_DATA = @DATAFILES_TRUE@@SYSTEMD_TRUE@systemdunitdir = @SYSTEMD_UNITDIR@ @DATAFILES_TRUE@@SYSTEMD_TRUE@systemdunit_DATA = src/bluetooth.service plugindir = $(libdir)/bluetooth/plugins @MAINTAINER_MODE_FALSE@build_plugindir = $(plugindir) @MAINTAINER_MODE_TRUE@build_plugindir = $(abs_top_srcdir)/plugins/.libs plugin_LTLIBRARIES = $(am__append_37) lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h lib/mgmt.h \ lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h lib/uuid.h \ lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h lib/a2mp.h local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file))) BUILT_SOURCES = $(local_headers) src/builtin.h lib_libbluetooth_la_SOURCES = $(lib_headers) \ lib/bluetooth.c lib/hci.c lib/sdp.c lib/uuid.c lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 16:0:13 lib_libbluetooth_la_DEPENDENCIES = $(local_headers) lib_libbluetooth_private_la_SOURCES = $(lib_libbluetooth_la_SOURCES) @SBC_TRUE@sbc_libsbc_la_SOURCES = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h sbc/sbc_tables.h \ @SBC_TRUE@ sbc/sbc_primitives.h sbc/sbc_primitives.c \ @SBC_TRUE@ sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \ @SBC_TRUE@ sbc/sbc_primitives_iwmmxt.h sbc/sbc_primitives_iwmmxt.c \ @SBC_TRUE@ sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \ @SBC_TRUE@ sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c @SBC_TRUE@sbc_libsbc_la_CFLAGS = $(AM_CFLAGS) -finline-functions -fgcse-after-reload \ @SBC_TRUE@ -funswitch-loops -funroll-loops @SBC_TRUE@sbc_sbcdec_SOURCES = sbc/sbcdec.c sbc/formats.h @SBC_TRUE@sbc_sbcdec_LDADD = sbc/libsbc.la @SBC_TRUE@sbc_sbcenc_SOURCES = sbc/sbcenc.c sbc/formats.h @SBC_TRUE@sbc_sbcenc_LDADD = sbc/libsbc.la @SBC_TRUE@@SNDFILE_TRUE@sbc_sbctester_LDADD = @SNDFILE_LIBS@ -lm @SBC_TRUE@@SNDFILE_TRUE@sbc_sbctest_CFLAGS = $(AM_CFLAGS) @SNDFILE_CFLAGS@ attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \ attrib/gatt.h attrib/gatt.c \ attrib/gattrib.h attrib/gattrib.c attrib/client.h \ attrib/client.c attrib/gatt-service.h attrib/gatt-service.c gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \ gdbus/object.c gdbus/polkit.c btio_sources = btio/btio.h btio/btio.c builtin_modules = $(am__append_5) $(am__append_7) $(am__append_11) \ $(am__append_15) $(am__append_17) $(am__append_19) \ $(am__append_21) $(am__append_23) $(am__append_25) hciops \ mgmtops $(am__append_27) $(am__append_29) storage adaptername \ $(am__append_31) $(am__append_33) $(am__append_35) builtin_sources = $(am__append_6) $(am__append_8) $(am__append_12) \ $(am__append_16) $(am__append_18) $(am__append_20) \ $(am__append_22) $(am__append_24) $(am__append_26) \ plugins/hciops.c plugins/mgmtops.c $(am__append_28) \ $(am__append_30) plugins/storage.c plugins/adaptername.c \ $(am__append_32) $(am__append_34) $(am__append_36) builtin_nodist = $(am__append_9) $(am__append_13) mcap_sources = $(am__append_4) @AUDIOPLUGIN_TRUE@audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \ @AUDIOPLUGIN_TRUE@ audio/telephony-maemo5.c audio/telephony-ofono.c \ @AUDIOPLUGIN_TRUE@ audio/telephony-maemo6.c @SAPPLUGIN_TRUE@sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c sap/sap-u8500.c @MAINTAINER_MODE_TRUE@plugins_external_dummy_la_SOURCES = plugins/external-dummy.c @MAINTAINER_MODE_TRUE@plugins_external_dummy_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \ @MAINTAINER_MODE_TRUE@ -no-undefined @MAINTAINER_MODE_TRUE@plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \ $(attrib_sources) $(btio_sources) \ $(mcap_sources) src/bluetooth.ver \ src/main.c src/log.h src/log.c \ src/rfkill.c src/hcid.h src/sdpd.h \ src/sdpd-server.c src/sdpd-request.c \ src/sdpd-service.c src/sdpd-database.c \ src/attrib-server.h src/attrib-server.c \ src/sdp-xml.h src/sdp-xml.c \ src/sdp-client.h src/sdp-client.c \ src/textfile.h src/textfile.c \ src/glib-helper.h src/glib-helper.c \ src/oui.h src/oui.c src/uinput.h src/ppoll.h \ src/plugin.h src/plugin.c \ src/storage.h src/storage.c \ src/agent.h src/agent.c \ src/error.h src/error.c \ src/manager.h src/manager.c \ src/adapter.h src/adapter.c \ src/device.h src/device.c src/attio.h \ src/dbus-common.c src/dbus-common.h \ src/event.h src/event.c \ src/oob.h src/oob.c src/eir.h src/eir.c src_bluetoothd_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @DBUS_LIBS@ \ -ldl -lrt src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \ -Wl,--version-script=$(srcdir)/src/bluetooth.ver src_bluetoothd_DEPENDENCIES = lib/libbluetooth-private.la src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \ -DPLUGINDIR=\""$(build_plugindir)"\" src_bluetoothd_SHORTNAME = bluetoothd builtin_files = src/builtin.h $(builtin_nodist) nodist_src_bluetoothd_SOURCES = $(builtin_files) man_MANS = src/bluetoothd.8 @ALSA_TRUE@alsadir = $(libdir)/alsa-lib @ALSA_TRUE@alsa_LTLIBRARIES = audio/libasound_module_pcm_bluetooth.la \ @ALSA_TRUE@ audio/libasound_module_ctl_bluetooth.la @ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_SOURCES = audio/pcm_bluetooth.c \ @ALSA_TRUE@ audio/rtp.h audio/ipc.h audio/ipc.c @ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module \ @ALSA_TRUE@ -avoid-version @ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_LIBADD = sbc/libsbc.la \ @ALSA_TRUE@ lib/libbluetooth-private.la @ALSA_LIBS@ @ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@ @ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_SOURCES = audio/ctl_bluetooth.c \ @ALSA_TRUE@ audio/rtp.h audio/ipc.h audio/ipc.c @ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module \ @ALSA_TRUE@ -avoid-version @ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_LIBADD = \ @ALSA_TRUE@ lib/libbluetooth-private.la @ALSA_LIBS@ @ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@ @ALSA_TRUE@@DATAFILES_TRUE@alsaconfdir = $(datadir)/alsa @ALSA_TRUE@@DATAFILES_TRUE@alsaconf_DATA = audio/bluetooth.conf @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@gstreamerdir = $(libdir)/gstreamer-0.10 @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@gstreamer_LTLIBRARIES = audio/libgstbluetooth.la @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_SOURCES = audio/gstbluetooth.c audio/gstpragma.h \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/gstsbcenc.h audio/gstsbcenc.c \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/gstsbcdec.h audio/gstsbcdec.c \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/gstsbcparse.h audio/gstsbcparse.c \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/gstavdtpsink.h audio/gstavdtpsink.c \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/gsta2dpsink.h audio/gsta2dpsink.c \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/gstsbcutil.h audio/gstsbcutil.c \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ audio/rtp.h audio/ipc.h audio/ipc.c @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_LIBADD = sbc/libsbc.la lib/libbluetooth-private.la \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ @DBUS_LIBS@ @GSTREAMER_LIBS@ \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ -lgstaudio-0.10 -lgstrtp-0.10 @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_CFLAGS = -fvisibility=hidden -fno-strict-aliasing \ @AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@ $(AM_CFLAGS) @DBUS_CFLAGS@ @GSTREAMER_CFLAGS@ @TOOLS_TRUE@tools_rfcomm_SOURCES = tools/rfcomm.c tools/parser.y tools/lexer.l \ @TOOLS_TRUE@ tools/kword.h tools/kword.c @TOOLS_TRUE@EXTRA_tools_rfcomm_SOURCES = tools/parser.h tools/parser.c \ @TOOLS_TRUE@ tools/lexer.c @TOOLS_TRUE@tools_rfcomm_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_l2ping_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \ @TOOLS_TRUE@ tools/hciattach_st.c \ @TOOLS_TRUE@ tools/hciattach_ti.c \ @TOOLS_TRUE@ tools/hciattach_tialt.c \ @TOOLS_TRUE@ tools/hciattach_ath3k.c \ @TOOLS_TRUE@ tools/hciattach_qualcomm.c \ @TOOLS_TRUE@ tools/hciattach_intel.c @TOOLS_TRUE@tools_hciattach_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \ @TOOLS_TRUE@ src/textfile.h src/textfile.c @TOOLS_TRUE@tools_hciconfig_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c \ @TOOLS_TRUE@ src/textfile.h src/textfile.c @TOOLS_TRUE@tools_hcitool_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c @TOOLS_TRUE@tools_sdptool_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_ciptool_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_avinfo_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_ppporc_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@tools_hcieventmask_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@mgmt_btmgmt_SOURCES = mgmt/main.c src/glib-helper.c @TOOLS_TRUE@mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @TOOLS_TRUE@monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \ @TOOLS_TRUE@ monitor/mainloop.h monitor/mainloop.c \ @TOOLS_TRUE@ monitor/hcidump.h monitor/hcidump.c \ @TOOLS_TRUE@ monitor/btsnoop.h monitor/btsnoop.c \ @TOOLS_TRUE@ monitor/control.h monitor/control.c \ @TOOLS_TRUE@ monitor/packet.h monitor/packet.c @TOOLS_TRUE@monitor_btmon_LDADD = lib/libbluetooth-private.la @TOOLS_TRUE@emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \ @TOOLS_TRUE@ monitor/mainloop.h monitor/mainloop.c \ @TOOLS_TRUE@ emulator/server.h emulator/server.c \ @TOOLS_TRUE@ emulator/vhci.h emulator/vhci.c \ @TOOLS_TRUE@ emulator/btdev.h emulator/btdev.c @READLINE_TRUE@@TOOLS_TRUE@attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/gattrib.c btio/btio.c \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/gatttool.h attrib/interactive.c \ @READLINE_TRUE@@TOOLS_TRUE@ attrib/utils.c src/log.c @READLINE_TRUE@@TOOLS_TRUE@attrib_gatttool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @READLINE_LIBS@ @BCCMD_TRUE@tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h \ @BCCMD_TRUE@ tools/csr.c tools/csr_hci.c tools/csr_h4.c \ @BCCMD_TRUE@ tools/csr_3wire.c tools/csr_bcsp.c tools/ubcsp.h \ @BCCMD_TRUE@ tools/ubcsp.c $(am__append_46) @BCCMD_TRUE@tools_bccmd_LDADD = lib/libbluetooth-private.la \ @BCCMD_TRUE@ $(am__append_47) @DATAFILES_TRUE@@PCMCIA_TRUE@udevdir = @UDEV_DIR@ @HID2HCI_TRUE@udevdir = @UDEV_DIR@ @HID2HCI_TRUE@tools_hid2hci_LDADD = @USB_LIBS@ @UDEV_LIBS@ @DFUTOOL_TRUE@tools_dfutool_SOURCES = tools/dfutool.c tools/dfu.h tools/dfu.c @DFUTOOL_TRUE@tools_dfutool_LDADD = @USB_LIBS@ @USB_TRUE@tools_dfubabel_LDADD = @USB_LIBS@ @USB_TRUE@tools_avctrl_LDADD = @USB_LIBS@ @CUPS_TRUE@cupsdir = $(libdir)/cups/backend @CUPS_TRUE@cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \ @CUPS_TRUE@ cups/sdp.c cups/spp.c cups/hcrp.c @CUPS_TRUE@cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth-private.la @TEST_TRUE@test_hciemu_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_l2test_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_rctest_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_gaptest_LDADD = @DBUS_LIBS@ @TEST_TRUE@test_sdptest_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_scotest_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_attest_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_hstest_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_avtest_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_lmptest_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_ipctest_SOURCES = test/ipctest.c audio/ipc.h audio/ipc.c @TEST_TRUE@test_ipctest_LDADD = @GLIB_LIBS@ sbc/libsbc.la @TEST_TRUE@test_bdaddr_SOURCES = test/bdaddr.c src/oui.h src/oui.c @TEST_TRUE@test_bdaddr_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_agent_LDADD = @DBUS_LIBS@ @TEST_TRUE@test_btiotest_SOURCES = test/btiotest.c btio/btio.h btio/btio.c @TEST_TRUE@test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la @TEST_TRUE@test_uuidtest_SOURCES = test/uuidtest.c @TEST_TRUE@test_uuidtest_LDADD = lib/libbluetooth-private.la @TEST_TRUE@test_mpris_player_SOURCES = test/mpris-player.c @TEST_TRUE@test_mpris_player_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @TEST_TRUE@test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c @HIDD_TRUE@compat_hidd_SOURCES = compat/hidd.c compat/hidd.h src/uinput.h \ @HIDD_TRUE@ compat/sdp.h compat/sdp.c compat/fakehid.c \ @HIDD_TRUE@ src/textfile.h src/textfile.c @HIDD_TRUE@compat_hidd_LDADD = -lm lib/libbluetooth-private.la @PAND_TRUE@compat_pand_SOURCES = compat/pand.c compat/pand.h \ @PAND_TRUE@ compat/bnep.c compat/sdp.h compat/sdp.c \ @PAND_TRUE@ src/textfile.h src/textfile.c @PAND_TRUE@compat_pand_LDADD = lib/libbluetooth-private.la @DUND_TRUE@compat_dund_SOURCES = compat/dund.c compat/dund.h compat/lib.h \ @DUND_TRUE@ compat/sdp.h compat/sdp.c compat/dun.c compat/msdun.c \ @DUND_TRUE@ src/textfile.h src/textfile.c @DUND_TRUE@compat_dund_LDADD = lib/libbluetooth-private.la @DATAFILES_TRUE@rulesdir = @UDEV_DIR@/rules.d @DATAFILES_TRUE@udev_files = $(am__append_71) $(am__append_72) @DATAFILES_TRUE@@PCMCIA_TRUE@dist_udev_SCRIPTS = scripts/bluetooth_serial @DATAFILES_TRUE@rules_DATA = $(foreach file,$(udev_files), scripts/97-$(notdir $(file))) AM_YFLAGS = -d INCLUDES = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \ -I$(srcdir)/audio -I$(srcdir)/sbc -I$(srcdir)/gdbus \ -I$(srcdir)/attrib -I$(srcdir)/btio -I$(srcdir)/tools \ -I$(builddir)/tools -I$(srcdir)/monitor $(am__append_73) unit_objects = $(am__append_74) @TEST_FALSE@unit_tests = @TEST_TRUE@unit_tests = unit/test-eir @TEST_TRUE@unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/glib-helper.c @TEST_TRUE@unit_test_eir_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @CHECK_LIBS@ @TEST_TRUE@unit_test_eir_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@ pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = bluez.pc DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles DISTCLEANFILES = $(pkgconfig_DATA) MAINTAINERCLEANFILES = Makefile.in \ aclocal.m4 configure config.h.in config.sub config.guess \ ltmain.sh depcomp compile missing install-sh mkinstalldirs ylwrap all: $(BUILT_SOURCES) config.h $(MAKE) $(AM_MAKEFLAGS) all-am .SUFFIXES: .SUFFIXES: .c .l .lo .o .obj .y am--refresh: Makefile @: $(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.tools $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(srcdir)/Makefile.tools: $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): config.h: stamp-h1 @if test ! -f $@; then rm -f stamp-h1; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) stamp-h1; else :; fi stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status config.h $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f config.h stamp-h1 doc/version.xml: $(top_builddir)/config.status $(top_srcdir)/doc/version.xml.in cd $(top_builddir) && $(SHELL) ./config.status $@ src/bluetoothd.8: $(top_builddir)/config.status $(top_srcdir)/src/bluetoothd.8.in cd $(top_builddir) && $(SHELL) ./config.status $@ src/bluetooth.service: $(top_builddir)/config.status $(top_srcdir)/src/bluetooth.service.in cd $(top_builddir) && $(SHELL) ./config.status $@ bluez.pc: $(top_builddir)/config.status $(srcdir)/bluez.pc.in cd $(top_builddir) && $(SHELL) ./config.status $@ clean-noinstLIBRARIES: -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) audio/$(am__dirstamp): @$(MKDIR_P) audio @: > audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) audio/$(DEPDIR) @: > audio/$(DEPDIR)/$(am__dirstamp) audio/telephony-dummy.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/telephony-maemo5.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/telephony-ofono.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/telephony-maemo6.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/libtelephony.a: $(audio_libtelephony_a_OBJECTS) $(audio_libtelephony_a_DEPENDENCIES) $(EXTRA_audio_libtelephony_a_DEPENDENCIES) audio/$(am__dirstamp) $(AM_V_at)-rm -f audio/libtelephony.a $(AM_V_AR)$(audio_libtelephony_a_AR) audio/libtelephony.a $(audio_libtelephony_a_OBJECTS) $(audio_libtelephony_a_LIBADD) $(AM_V_at)$(RANLIB) audio/libtelephony.a sap/$(am__dirstamp): @$(MKDIR_P) sap @: > sap/$(am__dirstamp) sap/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) sap/$(DEPDIR) @: > sap/$(DEPDIR)/$(am__dirstamp) sap/sap-dummy.$(OBJEXT): sap/$(am__dirstamp) \ sap/$(DEPDIR)/$(am__dirstamp) sap/sap-u8500.$(OBJEXT): sap/$(am__dirstamp) \ sap/$(DEPDIR)/$(am__dirstamp) sap/libsap.a: $(sap_libsap_a_OBJECTS) $(sap_libsap_a_DEPENDENCIES) $(EXTRA_sap_libsap_a_DEPENDENCIES) sap/$(am__dirstamp) $(AM_V_at)-rm -f sap/libsap.a $(AM_V_AR)$(sap_libsap_a_AR) sap/libsap.a $(sap_libsap_a_OBJECTS) $(sap_libsap_a_LIBADD) $(AM_V_at)$(RANLIB) sap/libsap.a install-alsaLTLIBRARIES: $(alsa_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(alsadir)" || $(MKDIR_P) "$(DESTDIR)$(alsadir)" @list='$(alsa_LTLIBRARIES)'; test -n "$(alsadir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(alsadir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(alsadir)"; \ } uninstall-alsaLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(alsa_LTLIBRARIES)'; test -n "$(alsadir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(alsadir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(alsadir)/$$f"; \ done clean-alsaLTLIBRARIES: -test -z "$(alsa_LTLIBRARIES)" || rm -f $(alsa_LTLIBRARIES) @list='$(alsa_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-gstreamerLTLIBRARIES: $(gstreamer_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(gstreamerdir)" || $(MKDIR_P) "$(DESTDIR)$(gstreamerdir)" @list='$(gstreamer_LTLIBRARIES)'; test -n "$(gstreamerdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(gstreamerdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(gstreamerdir)"; \ } uninstall-gstreamerLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(gstreamer_LTLIBRARIES)'; test -n "$(gstreamerdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(gstreamerdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(gstreamerdir)/$$f"; \ done clean-gstreamerLTLIBRARIES: -test -z "$(gstreamer_LTLIBRARIES)" || rm -f $(gstreamer_LTLIBRARIES) @list='$(gstreamer_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-libLTLIBRARIES: $(lib_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ } uninstall-libLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ done clean-libLTLIBRARIES: -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done clean-noinstLTLIBRARIES: -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES) @$(NORMAL_INSTALL) test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)" @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ list2=; for p in $$list; do \ if test -f $$p; then \ list2="$$list2 $$p"; \ else :; fi; \ done; \ test -z "$$list2" || { \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \ } uninstall-pluginLTLIBRARIES: @$(NORMAL_UNINSTALL) @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \ for p in $$list; do \ $(am__strip_dir) \ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \ done clean-pluginLTLIBRARIES: -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES) @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ test "$$dir" != "$$p" || dir=.; \ echo "rm -f \"$${dir}/so_locations\""; \ rm -f "$${dir}/so_locations"; \ done audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo: \ audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo: \ audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp) audio/libasound_module_ctl_bluetooth.la: $(audio_libasound_module_ctl_bluetooth_la_OBJECTS) $(audio_libasound_module_ctl_bluetooth_la_DEPENDENCIES) $(EXTRA_audio_libasound_module_ctl_bluetooth_la_DEPENDENCIES) audio/$(am__dirstamp) $(AM_V_CCLD)$(audio_libasound_module_ctl_bluetooth_la_LINK) $(am_audio_libasound_module_ctl_bluetooth_la_rpath) $(audio_libasound_module_ctl_bluetooth_la_OBJECTS) $(audio_libasound_module_ctl_bluetooth_la_LIBADD) $(LIBS) audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo: \ audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo: \ audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp) audio/libasound_module_pcm_bluetooth.la: $(audio_libasound_module_pcm_bluetooth_la_OBJECTS) $(audio_libasound_module_pcm_bluetooth_la_DEPENDENCIES) $(EXTRA_audio_libasound_module_pcm_bluetooth_la_DEPENDENCIES) audio/$(am__dirstamp) $(AM_V_CCLD)$(audio_libasound_module_pcm_bluetooth_la_LINK) $(am_audio_libasound_module_pcm_bluetooth_la_rpath) $(audio_libasound_module_pcm_bluetooth_la_OBJECTS) $(audio_libasound_module_pcm_bluetooth_la_LIBADD) $(LIBS) audio/audio_libgstbluetooth_la-gstbluetooth.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libgstbluetooth_la-gstsbcenc.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libgstbluetooth_la-gstsbcdec.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libgstbluetooth_la-gstsbcparse.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libgstbluetooth_la-gstavdtpsink.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libgstbluetooth_la-gsta2dpsink.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libgstbluetooth_la-gstsbcutil.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/audio_libgstbluetooth_la-ipc.lo: audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/libgstbluetooth.la: $(audio_libgstbluetooth_la_OBJECTS) $(audio_libgstbluetooth_la_DEPENDENCIES) $(EXTRA_audio_libgstbluetooth_la_DEPENDENCIES) audio/$(am__dirstamp) $(AM_V_CCLD)$(audio_libgstbluetooth_la_LINK) $(am_audio_libgstbluetooth_la_rpath) $(audio_libgstbluetooth_la_OBJECTS) $(audio_libgstbluetooth_la_LIBADD) $(LIBS) lib/$(am__dirstamp): @$(MKDIR_P) lib @: > lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) lib/$(DEPDIR) @: > lib/$(DEPDIR)/$(am__dirstamp) lib/bluetooth.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) lib/hci.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) lib/sdp.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) lib/uuid.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp) lib/libbluetooth-private.la: $(lib_libbluetooth_private_la_OBJECTS) $(lib_libbluetooth_private_la_DEPENDENCIES) $(EXTRA_lib_libbluetooth_private_la_DEPENDENCIES) lib/$(am__dirstamp) $(AM_V_CCLD)$(LINK) $(lib_libbluetooth_private_la_OBJECTS) $(lib_libbluetooth_private_la_LIBADD) $(LIBS) lib/libbluetooth.la: $(lib_libbluetooth_la_OBJECTS) $(lib_libbluetooth_la_DEPENDENCIES) $(EXTRA_lib_libbluetooth_la_DEPENDENCIES) lib/$(am__dirstamp) $(AM_V_CCLD)$(lib_libbluetooth_la_LINK) -rpath $(libdir) $(lib_libbluetooth_la_OBJECTS) $(lib_libbluetooth_la_LIBADD) $(LIBS) plugins/$(am__dirstamp): @$(MKDIR_P) plugins @: > plugins/$(am__dirstamp) plugins/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) plugins/$(DEPDIR) @: > plugins/$(DEPDIR)/$(am__dirstamp) plugins/plugins_external_dummy_la-external-dummy.lo: \ plugins/$(am__dirstamp) plugins/$(DEPDIR)/$(am__dirstamp) plugins/external-dummy.la: $(plugins_external_dummy_la_OBJECTS) $(plugins_external_dummy_la_DEPENDENCIES) $(EXTRA_plugins_external_dummy_la_DEPENDENCIES) plugins/$(am__dirstamp) $(AM_V_CCLD)$(plugins_external_dummy_la_LINK) $(am_plugins_external_dummy_la_rpath) $(plugins_external_dummy_la_OBJECTS) $(plugins_external_dummy_la_LIBADD) $(LIBS) sbc/$(am__dirstamp): @$(MKDIR_P) sbc @: > sbc/$(am__dirstamp) sbc/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) sbc/$(DEPDIR) @: > sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbc_libsbc_la-sbc.lo: sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbc_libsbc_la-sbc_primitives.lo: sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbc_libsbc_la-sbc_primitives_mmx.lo: sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo: sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbc_libsbc_la-sbc_primitives_neon.lo: sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbc_libsbc_la-sbc_primitives_armv6.lo: sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/libsbc.la: $(sbc_libsbc_la_OBJECTS) $(sbc_libsbc_la_DEPENDENCIES) $(EXTRA_sbc_libsbc_la_DEPENDENCIES) sbc/$(am__dirstamp) $(AM_V_CCLD)$(sbc_libsbc_la_LINK) $(am_sbc_libsbc_la_rpath) $(sbc_libsbc_la_OBJECTS) $(sbc_libsbc_la_LIBADD) $(LIBS) install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-cupsPROGRAMS: $(cups_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(cupsdir)" || $(MKDIR_P) "$(DESTDIR)$(cupsdir)" @list='$(cups_PROGRAMS)'; test -n "$(cupsdir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(cupsdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(cupsdir)$$dir" || exit $$?; \ } \ ; done uninstall-cupsPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(cups_PROGRAMS)'; test -n "$(cupsdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(cupsdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(cupsdir)" && rm -f $$files clean-cupsPROGRAMS: @list='$(cups_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list clean-noinstPROGRAMS: @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-sbinPROGRAMS: $(sbin_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)" @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ } \ ; done uninstall-sbinPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(sbindir)" && rm -f $$files clean-sbinPROGRAMS: @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list install-udevPROGRAMS: $(udev_PROGRAMS) @$(NORMAL_INSTALL) test -z "$(udevdir)" || $(MKDIR_P) "$(DESTDIR)$(udevdir)" @list='$(udev_PROGRAMS)'; test -n "$(udevdir)" || list=; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p || test -f $$p1; \ then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(udevdir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(udevdir)$$dir" || exit $$?; \ } \ ; done uninstall-udevPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(udev_PROGRAMS)'; test -n "$(udevdir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(udevdir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(udevdir)" && rm -f $$files clean-udevPROGRAMS: @list='$(udev_PROGRAMS)'; test -n "$$list" || exit 0; \ echo " rm -f" $$list; \ rm -f $$list || exit $$?; \ test -n "$(EXEEXT)" || exit 0; \ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ echo " rm -f" $$list; \ rm -f $$list attrib/$(am__dirstamp): @$(MKDIR_P) attrib @: > attrib/$(am__dirstamp) attrib/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) attrib/$(DEPDIR) @: > attrib/$(DEPDIR)/$(am__dirstamp) attrib/gatttool.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/att.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/gatt.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/gattrib.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) btio/$(am__dirstamp): @$(MKDIR_P) btio @: > btio/$(am__dirstamp) btio/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) btio/$(DEPDIR) @: > btio/$(DEPDIR)/$(am__dirstamp) btio/btio.$(OBJEXT): btio/$(am__dirstamp) \ btio/$(DEPDIR)/$(am__dirstamp) attrib/interactive.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/utils.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) src/$(am__dirstamp): @$(MKDIR_P) src @: > src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) src/$(DEPDIR) @: > src/$(DEPDIR)/$(am__dirstamp) src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) attrib/gatttool$(EXEEXT): $(attrib_gatttool_OBJECTS) $(attrib_gatttool_DEPENDENCIES) $(EXTRA_attrib_gatttool_DEPENDENCIES) attrib/$(am__dirstamp) @rm -f attrib/gatttool$(EXEEXT) $(AM_V_CCLD)$(LINK) $(attrib_gatttool_OBJECTS) $(attrib_gatttool_LDADD) $(LIBS) compat/$(am__dirstamp): @$(MKDIR_P) compat @: > compat/$(am__dirstamp) compat/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) compat/$(DEPDIR) @: > compat/$(DEPDIR)/$(am__dirstamp) compat/dund.$(OBJEXT): compat/$(am__dirstamp) \ compat/$(DEPDIR)/$(am__dirstamp) compat/sdp.$(OBJEXT): compat/$(am__dirstamp) \ compat/$(DEPDIR)/$(am__dirstamp) compat/dun.$(OBJEXT): compat/$(am__dirstamp) \ compat/$(DEPDIR)/$(am__dirstamp) compat/msdun.$(OBJEXT): compat/$(am__dirstamp) \ compat/$(DEPDIR)/$(am__dirstamp) src/textfile.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) compat/dund$(EXEEXT): $(compat_dund_OBJECTS) $(compat_dund_DEPENDENCIES) $(EXTRA_compat_dund_DEPENDENCIES) compat/$(am__dirstamp) @rm -f compat/dund$(EXEEXT) $(AM_V_CCLD)$(LINK) $(compat_dund_OBJECTS) $(compat_dund_LDADD) $(LIBS) compat/hidd.$(OBJEXT): compat/$(am__dirstamp) \ compat/$(DEPDIR)/$(am__dirstamp) compat/fakehid.$(OBJEXT): compat/$(am__dirstamp) \ compat/$(DEPDIR)/$(am__dirstamp) compat/hidd$(EXEEXT): $(compat_hidd_OBJECTS) $(compat_hidd_DEPENDENCIES) $(EXTRA_compat_hidd_DEPENDENCIES) compat/$(am__dirstamp) @rm -f compat/hidd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(compat_hidd_OBJECTS) $(compat_hidd_LDADD) $(LIBS) compat/pand.$(OBJEXT): compat/$(am__dirstamp) \ compat/$(DEPDIR)/$(am__dirstamp) compat/bnep.$(OBJEXT): compat/$(am__dirstamp) \ compat/$(DEPDIR)/$(am__dirstamp) compat/pand$(EXEEXT): $(compat_pand_OBJECTS) $(compat_pand_DEPENDENCIES) $(EXTRA_compat_pand_DEPENDENCIES) compat/$(am__dirstamp) @rm -f compat/pand$(EXEEXT) $(AM_V_CCLD)$(LINK) $(compat_pand_OBJECTS) $(compat_pand_LDADD) $(LIBS) gdbus/$(am__dirstamp): @$(MKDIR_P) gdbus @: > gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) gdbus/$(DEPDIR) @: > gdbus/$(DEPDIR)/$(am__dirstamp) gdbus/mainloop.$(OBJEXT): gdbus/$(am__dirstamp) \ gdbus/$(DEPDIR)/$(am__dirstamp) gdbus/watch.$(OBJEXT): gdbus/$(am__dirstamp) \ gdbus/$(DEPDIR)/$(am__dirstamp) gdbus/object.$(OBJEXT): gdbus/$(am__dirstamp) \ gdbus/$(DEPDIR)/$(am__dirstamp) gdbus/polkit.$(OBJEXT): gdbus/$(am__dirstamp) \ gdbus/$(DEPDIR)/$(am__dirstamp) cups/$(am__dirstamp): @$(MKDIR_P) cups @: > cups/$(am__dirstamp) cups/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) cups/$(DEPDIR) @: > cups/$(DEPDIR)/$(am__dirstamp) cups/main.$(OBJEXT): cups/$(am__dirstamp) \ cups/$(DEPDIR)/$(am__dirstamp) cups/sdp.$(OBJEXT): cups/$(am__dirstamp) \ cups/$(DEPDIR)/$(am__dirstamp) cups/spp.$(OBJEXT): cups/$(am__dirstamp) \ cups/$(DEPDIR)/$(am__dirstamp) cups/hcrp.$(OBJEXT): cups/$(am__dirstamp) \ cups/$(DEPDIR)/$(am__dirstamp) cups/bluetooth$(EXEEXT): $(cups_bluetooth_OBJECTS) $(cups_bluetooth_DEPENDENCIES) $(EXTRA_cups_bluetooth_DEPENDENCIES) cups/$(am__dirstamp) @rm -f cups/bluetooth$(EXEEXT) $(AM_V_CCLD)$(LINK) $(cups_bluetooth_OBJECTS) $(cups_bluetooth_LDADD) $(LIBS) emulator/$(am__dirstamp): @$(MKDIR_P) emulator @: > emulator/$(am__dirstamp) emulator/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) emulator/$(DEPDIR) @: > emulator/$(DEPDIR)/$(am__dirstamp) emulator/main.$(OBJEXT): emulator/$(am__dirstamp) \ emulator/$(DEPDIR)/$(am__dirstamp) monitor/$(am__dirstamp): @$(MKDIR_P) monitor @: > monitor/$(am__dirstamp) monitor/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) monitor/$(DEPDIR) @: > monitor/$(DEPDIR)/$(am__dirstamp) monitor/mainloop.$(OBJEXT): monitor/$(am__dirstamp) \ monitor/$(DEPDIR)/$(am__dirstamp) emulator/server.$(OBJEXT): emulator/$(am__dirstamp) \ emulator/$(DEPDIR)/$(am__dirstamp) emulator/vhci.$(OBJEXT): emulator/$(am__dirstamp) \ emulator/$(DEPDIR)/$(am__dirstamp) emulator/btdev.$(OBJEXT): emulator/$(am__dirstamp) \ emulator/$(DEPDIR)/$(am__dirstamp) emulator/btvirt$(EXEEXT): $(emulator_btvirt_OBJECTS) $(emulator_btvirt_DEPENDENCIES) $(EXTRA_emulator_btvirt_DEPENDENCIES) emulator/$(am__dirstamp) @rm -f emulator/btvirt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(emulator_btvirt_OBJECTS) $(emulator_btvirt_LDADD) $(LIBS) mgmt/$(am__dirstamp): @$(MKDIR_P) mgmt @: > mgmt/$(am__dirstamp) mgmt/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) mgmt/$(DEPDIR) @: > mgmt/$(DEPDIR)/$(am__dirstamp) mgmt/main.$(OBJEXT): mgmt/$(am__dirstamp) \ mgmt/$(DEPDIR)/$(am__dirstamp) src/glib-helper.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) mgmt/btmgmt$(EXEEXT): $(mgmt_btmgmt_OBJECTS) $(mgmt_btmgmt_DEPENDENCIES) $(EXTRA_mgmt_btmgmt_DEPENDENCIES) mgmt/$(am__dirstamp) @rm -f mgmt/btmgmt$(EXEEXT) $(AM_V_CCLD)$(LINK) $(mgmt_btmgmt_OBJECTS) $(mgmt_btmgmt_LDADD) $(LIBS) monitor/main.$(OBJEXT): monitor/$(am__dirstamp) \ monitor/$(DEPDIR)/$(am__dirstamp) monitor/hcidump.$(OBJEXT): monitor/$(am__dirstamp) \ monitor/$(DEPDIR)/$(am__dirstamp) monitor/btsnoop.$(OBJEXT): monitor/$(am__dirstamp) \ monitor/$(DEPDIR)/$(am__dirstamp) monitor/control.$(OBJEXT): monitor/$(am__dirstamp) \ monitor/$(DEPDIR)/$(am__dirstamp) monitor/packet.$(OBJEXT): monitor/$(am__dirstamp) \ monitor/$(DEPDIR)/$(am__dirstamp) monitor/btmon$(EXEEXT): $(monitor_btmon_OBJECTS) $(monitor_btmon_DEPENDENCIES) $(EXTRA_monitor_btmon_DEPENDENCIES) monitor/$(am__dirstamp) @rm -f monitor/btmon$(EXEEXT) $(AM_V_CCLD)$(LINK) $(monitor_btmon_OBJECTS) $(monitor_btmon_LDADD) $(LIBS) sbc/sbcdec.$(OBJEXT): sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbcdec$(EXEEXT): $(sbc_sbcdec_OBJECTS) $(sbc_sbcdec_DEPENDENCIES) $(EXTRA_sbc_sbcdec_DEPENDENCIES) sbc/$(am__dirstamp) @rm -f sbc/sbcdec$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sbc_sbcdec_OBJECTS) $(sbc_sbcdec_LDADD) $(LIBS) sbc/sbcenc.$(OBJEXT): sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbcenc$(EXEEXT): $(sbc_sbcenc_OBJECTS) $(sbc_sbcenc_DEPENDENCIES) $(EXTRA_sbc_sbcenc_DEPENDENCIES) sbc/$(am__dirstamp) @rm -f sbc/sbcenc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sbc_sbcenc_OBJECTS) $(sbc_sbcenc_LDADD) $(LIBS) sbc/sbcinfo.$(OBJEXT): sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbcinfo$(EXEEXT): $(sbc_sbcinfo_OBJECTS) $(sbc_sbcinfo_DEPENDENCIES) $(EXTRA_sbc_sbcinfo_DEPENDENCIES) sbc/$(am__dirstamp) @rm -f sbc/sbcinfo$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sbc_sbcinfo_OBJECTS) $(sbc_sbcinfo_LDADD) $(LIBS) sbc/sbctester.$(OBJEXT): sbc/$(am__dirstamp) \ sbc/$(DEPDIR)/$(am__dirstamp) sbc/sbctester$(EXEEXT): $(sbc_sbctester_OBJECTS) $(sbc_sbctester_DEPENDENCIES) $(EXTRA_sbc_sbctester_DEPENDENCIES) sbc/$(am__dirstamp) @rm -f sbc/sbctester$(EXEEXT) $(AM_V_CCLD)$(LINK) $(sbc_sbctester_OBJECTS) $(sbc_sbctester_LDADD) $(LIBS) gdbus/bluetoothd-mainloop.$(OBJEXT): gdbus/$(am__dirstamp) \ gdbus/$(DEPDIR)/$(am__dirstamp) gdbus/bluetoothd-watch.$(OBJEXT): gdbus/$(am__dirstamp) \ gdbus/$(DEPDIR)/$(am__dirstamp) gdbus/bluetoothd-object.$(OBJEXT): gdbus/$(am__dirstamp) \ gdbus/$(DEPDIR)/$(am__dirstamp) gdbus/bluetoothd-polkit.$(OBJEXT): gdbus/$(am__dirstamp) \ gdbus/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-pnat.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-main.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-manager.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-gateway.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-headset.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-control.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-avctp.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-avrcp.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-device.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-source.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-sink.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-a2dp.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-avdtp.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-ipc.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-unix.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-media.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-transport.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) sap/bluetoothd-main.$(OBJEXT): sap/$(am__dirstamp) \ sap/$(DEPDIR)/$(am__dirstamp) sap/bluetoothd-manager.$(OBJEXT): sap/$(am__dirstamp) \ sap/$(DEPDIR)/$(am__dirstamp) sap/bluetoothd-server.$(OBJEXT): sap/$(am__dirstamp) \ sap/$(DEPDIR)/$(am__dirstamp) input/$(am__dirstamp): @$(MKDIR_P) input @: > input/$(am__dirstamp) input/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) input/$(DEPDIR) @: > input/$(DEPDIR)/$(am__dirstamp) input/bluetoothd-main.$(OBJEXT): input/$(am__dirstamp) \ input/$(DEPDIR)/$(am__dirstamp) input/bluetoothd-manager.$(OBJEXT): input/$(am__dirstamp) \ input/$(DEPDIR)/$(am__dirstamp) input/bluetoothd-server.$(OBJEXT): input/$(am__dirstamp) \ input/$(DEPDIR)/$(am__dirstamp) input/bluetoothd-device.$(OBJEXT): input/$(am__dirstamp) \ input/$(DEPDIR)/$(am__dirstamp) input/bluetoothd-fakehid.$(OBJEXT): input/$(am__dirstamp) \ input/$(DEPDIR)/$(am__dirstamp) serial/$(am__dirstamp): @$(MKDIR_P) serial @: > serial/$(am__dirstamp) serial/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) serial/$(DEPDIR) @: > serial/$(DEPDIR)/$(am__dirstamp) serial/bluetoothd-main.$(OBJEXT): serial/$(am__dirstamp) \ serial/$(DEPDIR)/$(am__dirstamp) serial/bluetoothd-manager.$(OBJEXT): serial/$(am__dirstamp) \ serial/$(DEPDIR)/$(am__dirstamp) serial/bluetoothd-proxy.$(OBJEXT): serial/$(am__dirstamp) \ serial/$(DEPDIR)/$(am__dirstamp) serial/bluetoothd-port.$(OBJEXT): serial/$(am__dirstamp) \ serial/$(DEPDIR)/$(am__dirstamp) network/$(am__dirstamp): @$(MKDIR_P) network @: > network/$(am__dirstamp) network/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) network/$(DEPDIR) @: > network/$(DEPDIR)/$(am__dirstamp) network/bluetoothd-main.$(OBJEXT): network/$(am__dirstamp) \ network/$(DEPDIR)/$(am__dirstamp) network/bluetoothd-manager.$(OBJEXT): network/$(am__dirstamp) \ network/$(DEPDIR)/$(am__dirstamp) network/bluetoothd-common.$(OBJEXT): network/$(am__dirstamp) \ network/$(DEPDIR)/$(am__dirstamp) network/bluetoothd-server.$(OBJEXT): network/$(am__dirstamp) \ network/$(DEPDIR)/$(am__dirstamp) network/bluetoothd-connection.$(OBJEXT): network/$(am__dirstamp) \ network/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-service.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) health/$(am__dirstamp): @$(MKDIR_P) health @: > health/$(am__dirstamp) health/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) health/$(DEPDIR) @: > health/$(DEPDIR)/$(am__dirstamp) health/bluetoothd-hdp_main.$(OBJEXT): health/$(am__dirstamp) \ health/$(DEPDIR)/$(am__dirstamp) health/bluetoothd-hdp_manager.$(OBJEXT): health/$(am__dirstamp) \ health/$(DEPDIR)/$(am__dirstamp) health/bluetoothd-hdp.$(OBJEXT): health/$(am__dirstamp) \ health/$(DEPDIR)/$(am__dirstamp) health/bluetoothd-hdp_util.$(OBJEXT): health/$(am__dirstamp) \ health/$(DEPDIR)/$(am__dirstamp) thermometer/$(am__dirstamp): @$(MKDIR_P) thermometer @: > thermometer/$(am__dirstamp) thermometer/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) thermometer/$(DEPDIR) @: > thermometer/$(DEPDIR)/$(am__dirstamp) thermometer/bluetoothd-main.$(OBJEXT): thermometer/$(am__dirstamp) \ thermometer/$(DEPDIR)/$(am__dirstamp) thermometer/bluetoothd-manager.$(OBJEXT): thermometer/$(am__dirstamp) \ thermometer/$(DEPDIR)/$(am__dirstamp) thermometer/bluetoothd-thermometer.$(OBJEXT): \ thermometer/$(am__dirstamp) \ thermometer/$(DEPDIR)/$(am__dirstamp) alert/$(am__dirstamp): @$(MKDIR_P) alert @: > alert/$(am__dirstamp) alert/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) alert/$(DEPDIR) @: > alert/$(DEPDIR)/$(am__dirstamp) alert/bluetoothd-main.$(OBJEXT): alert/$(am__dirstamp) \ alert/$(DEPDIR)/$(am__dirstamp) alert/bluetoothd-server.$(OBJEXT): alert/$(am__dirstamp) \ alert/$(DEPDIR)/$(am__dirstamp) time/$(am__dirstamp): @$(MKDIR_P) time @: > time/$(am__dirstamp) time/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) time/$(DEPDIR) @: > time/$(DEPDIR)/$(am__dirstamp) time/bluetoothd-main.$(OBJEXT): time/$(am__dirstamp) \ time/$(DEPDIR)/$(am__dirstamp) time/bluetoothd-server.$(OBJEXT): time/$(am__dirstamp) \ time/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-gatt-example.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) proximity/$(am__dirstamp): @$(MKDIR_P) proximity @: > proximity/$(am__dirstamp) proximity/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) proximity/$(DEPDIR) @: > proximity/$(DEPDIR)/$(am__dirstamp) proximity/bluetoothd-main.$(OBJEXT): proximity/$(am__dirstamp) \ proximity/$(DEPDIR)/$(am__dirstamp) proximity/bluetoothd-manager.$(OBJEXT): proximity/$(am__dirstamp) \ proximity/$(DEPDIR)/$(am__dirstamp) proximity/bluetoothd-monitor.$(OBJEXT): proximity/$(am__dirstamp) \ proximity/$(DEPDIR)/$(am__dirstamp) proximity/bluetoothd-reporter.$(OBJEXT): proximity/$(am__dirstamp) \ proximity/$(DEPDIR)/$(am__dirstamp) proximity/bluetoothd-linkloss.$(OBJEXT): proximity/$(am__dirstamp) \ proximity/$(DEPDIR)/$(am__dirstamp) proximity/bluetoothd-immalert.$(OBJEXT): proximity/$(am__dirstamp) \ proximity/$(DEPDIR)/$(am__dirstamp) deviceinfo/$(am__dirstamp): @$(MKDIR_P) deviceinfo @: > deviceinfo/$(am__dirstamp) deviceinfo/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) deviceinfo/$(DEPDIR) @: > deviceinfo/$(DEPDIR)/$(am__dirstamp) deviceinfo/bluetoothd-main.$(OBJEXT): deviceinfo/$(am__dirstamp) \ deviceinfo/$(DEPDIR)/$(am__dirstamp) deviceinfo/bluetoothd-manager.$(OBJEXT): deviceinfo/$(am__dirstamp) \ deviceinfo/$(DEPDIR)/$(am__dirstamp) deviceinfo/bluetoothd-deviceinfo.$(OBJEXT): \ deviceinfo/$(am__dirstamp) \ deviceinfo/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-hciops.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-mgmtops.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-hal.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-formfactor.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-storage.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-adaptername.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-wiimote.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-maemo6.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) plugins/bluetoothd-dbusoob.$(OBJEXT): plugins/$(am__dirstamp) \ plugins/$(DEPDIR)/$(am__dirstamp) attrib/bluetoothd-att.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/bluetoothd-gatt.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/bluetoothd-gattrib.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/bluetoothd-client.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) attrib/bluetoothd-gatt-service.$(OBJEXT): attrib/$(am__dirstamp) \ attrib/$(DEPDIR)/$(am__dirstamp) btio/bluetoothd-btio.$(OBJEXT): btio/$(am__dirstamp) \ btio/$(DEPDIR)/$(am__dirstamp) health/bluetoothd-mcap.$(OBJEXT): health/$(am__dirstamp) \ health/$(DEPDIR)/$(am__dirstamp) health/bluetoothd-mcap_sync.$(OBJEXT): health/$(am__dirstamp) \ health/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-main.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-log.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-rfkill.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-sdpd-server.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-sdpd-request.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-sdpd-service.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-sdpd-database.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-attrib-server.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-sdp-xml.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-sdp-client.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-textfile.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-glib-helper.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-oui.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-plugin.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-storage.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-agent.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-error.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-manager.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-adapter.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-device.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-dbus-common.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-event.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-oob.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/bluetoothd-eir.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) audio/bluetoothd-telephony.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) sap/bluetoothd-sap.$(OBJEXT): sap/$(am__dirstamp) \ sap/$(DEPDIR)/$(am__dirstamp) src/bluetoothd$(EXEEXT): $(src_bluetoothd_OBJECTS) $(src_bluetoothd_DEPENDENCIES) $(EXTRA_src_bluetoothd_DEPENDENCIES) src/$(am__dirstamp) @rm -f src/bluetoothd$(EXEEXT) $(AM_V_CCLD)$(src_bluetoothd_LINK) $(src_bluetoothd_OBJECTS) $(src_bluetoothd_LDADD) $(LIBS) test/$(am__dirstamp): @$(MKDIR_P) test @: > test/$(am__dirstamp) test/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) test/$(DEPDIR) @: > test/$(DEPDIR)/$(am__dirstamp) test/agent.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/agent$(EXEEXT): $(test_agent_OBJECTS) $(test_agent_DEPENDENCIES) $(EXTRA_test_agent_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/agent$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_agent_OBJECTS) $(test_agent_LDADD) $(LIBS) test/attest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/attest$(EXEEXT): $(test_attest_OBJECTS) $(test_attest_DEPENDENCIES) $(EXTRA_test_attest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/attest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_attest_OBJECTS) $(test_attest_LDADD) $(LIBS) test/avtest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/avtest$(EXEEXT): $(test_avtest_OBJECTS) $(test_avtest_DEPENDENCIES) $(EXTRA_test_avtest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/avtest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_avtest_OBJECTS) $(test_avtest_LDADD) $(LIBS) test/bdaddr.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) src/oui.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp) test/bdaddr$(EXEEXT): $(test_bdaddr_OBJECTS) $(test_bdaddr_DEPENDENCIES) $(EXTRA_test_bdaddr_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/bdaddr$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_bdaddr_OBJECTS) $(test_bdaddr_LDADD) $(LIBS) test/btiotest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/btiotest$(EXEEXT): $(test_btiotest_OBJECTS) $(test_btiotest_DEPENDENCIES) $(EXTRA_test_btiotest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/btiotest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_btiotest_OBJECTS) $(test_btiotest_LDADD) $(LIBS) test/gaptest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/gaptest$(EXEEXT): $(test_gaptest_OBJECTS) $(test_gaptest_DEPENDENCIES) $(EXTRA_test_gaptest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/gaptest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_gaptest_OBJECTS) $(test_gaptest_LDADD) $(LIBS) test/hciemu.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/hciemu$(EXEEXT): $(test_hciemu_OBJECTS) $(test_hciemu_DEPENDENCIES) $(EXTRA_test_hciemu_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/hciemu$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_hciemu_OBJECTS) $(test_hciemu_LDADD) $(LIBS) test/hstest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/hstest$(EXEEXT): $(test_hstest_OBJECTS) $(test_hstest_DEPENDENCIES) $(EXTRA_test_hstest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/hstest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_hstest_OBJECTS) $(test_hstest_LDADD) $(LIBS) test/ipctest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) audio/ipc.$(OBJEXT): audio/$(am__dirstamp) \ audio/$(DEPDIR)/$(am__dirstamp) test/ipctest$(EXEEXT): $(test_ipctest_OBJECTS) $(test_ipctest_DEPENDENCIES) $(EXTRA_test_ipctest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/ipctest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_ipctest_OBJECTS) $(test_ipctest_LDADD) $(LIBS) test/l2test.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/l2test$(EXEEXT): $(test_l2test_OBJECTS) $(test_l2test_DEPENDENCIES) $(EXTRA_test_l2test_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/l2test$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_l2test_OBJECTS) $(test_l2test_LDADD) $(LIBS) test/lmptest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/lmptest$(EXEEXT): $(test_lmptest_OBJECTS) $(test_lmptest_DEPENDENCIES) $(EXTRA_test_lmptest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/lmptest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_lmptest_OBJECTS) $(test_lmptest_LDADD) $(LIBS) test/mpris-player.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/mpris-player$(EXEEXT): $(test_mpris_player_OBJECTS) $(test_mpris_player_DEPENDENCIES) $(EXTRA_test_mpris_player_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/mpris-player$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_mpris_player_OBJECTS) $(test_mpris_player_LDADD) $(LIBS) test/rctest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/rctest$(EXEEXT): $(test_rctest_OBJECTS) $(test_rctest_DEPENDENCIES) $(EXTRA_test_rctest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/rctest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_rctest_OBJECTS) $(test_rctest_LDADD) $(LIBS) test/scotest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/scotest$(EXEEXT): $(test_scotest_OBJECTS) $(test_scotest_DEPENDENCIES) $(EXTRA_test_scotest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/scotest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_scotest_OBJECTS) $(test_scotest_LDADD) $(LIBS) test/sdptest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/sdptest$(EXEEXT): $(test_sdptest_OBJECTS) $(test_sdptest_DEPENDENCIES) $(EXTRA_test_sdptest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/sdptest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_sdptest_OBJECTS) $(test_sdptest_LDADD) $(LIBS) test/test-textfile.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/test-textfile$(EXEEXT): $(test_test_textfile_OBJECTS) $(test_test_textfile_DEPENDENCIES) $(EXTRA_test_test_textfile_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/test-textfile$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_test_textfile_OBJECTS) $(test_test_textfile_LDADD) $(LIBS) test/uuidtest.$(OBJEXT): test/$(am__dirstamp) \ test/$(DEPDIR)/$(am__dirstamp) test/uuidtest$(EXEEXT): $(test_uuidtest_OBJECTS) $(test_uuidtest_DEPENDENCIES) $(EXTRA_test_uuidtest_DEPENDENCIES) test/$(am__dirstamp) @rm -f test/uuidtest$(EXEEXT) $(AM_V_CCLD)$(LINK) $(test_uuidtest_OBJECTS) $(test_uuidtest_LDADD) $(LIBS) tools/$(am__dirstamp): @$(MKDIR_P) tools @: > tools/$(am__dirstamp) tools/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) tools/$(DEPDIR) @: > tools/$(DEPDIR)/$(am__dirstamp) tools/avctrl.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/avctrl$(EXEEXT): $(tools_avctrl_OBJECTS) $(tools_avctrl_DEPENDENCIES) $(EXTRA_tools_avctrl_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/avctrl$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_avctrl_OBJECTS) $(tools_avctrl_LDADD) $(LIBS) tools/avinfo.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/avinfo$(EXEEXT): $(tools_avinfo_OBJECTS) $(tools_avinfo_DEPENDENCIES) $(EXTRA_tools_avinfo_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/avinfo$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_avinfo_OBJECTS) $(tools_avinfo_LDADD) $(LIBS) tools/bccmd.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/csr.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/csr_hci.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/csr_h4.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/csr_3wire.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/csr_bcsp.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/ubcsp.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/csr_usb.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/bccmd$(EXEEXT): $(tools_bccmd_OBJECTS) $(tools_bccmd_DEPENDENCIES) $(EXTRA_tools_bccmd_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/bccmd$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_bccmd_OBJECTS) $(tools_bccmd_LDADD) $(LIBS) tools/ciptool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/ciptool$(EXEEXT): $(tools_ciptool_OBJECTS) $(tools_ciptool_DEPENDENCIES) $(EXTRA_tools_ciptool_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/ciptool$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_ciptool_OBJECTS) $(tools_ciptool_LDADD) $(LIBS) tools/dfubabel.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/dfubabel$(EXEEXT): $(tools_dfubabel_OBJECTS) $(tools_dfubabel_DEPENDENCIES) $(EXTRA_tools_dfubabel_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/dfubabel$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_dfubabel_OBJECTS) $(tools_dfubabel_LDADD) $(LIBS) tools/dfutool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/dfu.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/dfutool$(EXEEXT): $(tools_dfutool_OBJECTS) $(tools_dfutool_DEPENDENCIES) $(EXTRA_tools_dfutool_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/dfutool$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_dfutool_OBJECTS) $(tools_dfutool_LDADD) $(LIBS) tools/hciattach.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hciattach_st.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hciattach_ti.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hciattach_tialt.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hciattach_ath3k.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hciattach_qualcomm.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hciattach_intel.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hciattach$(EXEEXT): $(tools_hciattach_OBJECTS) $(tools_hciattach_DEPENDENCIES) $(EXTRA_tools_hciattach_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/hciattach$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_hciattach_OBJECTS) $(tools_hciattach_LDADD) $(LIBS) tools/hciconfig.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hciconfig$(EXEEXT): $(tools_hciconfig_OBJECTS) $(tools_hciconfig_DEPENDENCIES) $(EXTRA_tools_hciconfig_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/hciconfig$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_hciconfig_OBJECTS) $(tools_hciconfig_LDADD) $(LIBS) tools/hcieventmask.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hcieventmask$(EXEEXT): $(tools_hcieventmask_OBJECTS) $(tools_hcieventmask_DEPENDENCIES) $(EXTRA_tools_hcieventmask_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/hcieventmask$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_hcieventmask_OBJECTS) $(tools_hcieventmask_LDADD) $(LIBS) tools/hcisecfilter.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hcisecfilter$(EXEEXT): $(tools_hcisecfilter_OBJECTS) $(tools_hcisecfilter_DEPENDENCIES) $(EXTRA_tools_hcisecfilter_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/hcisecfilter$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_hcisecfilter_OBJECTS) $(tools_hcisecfilter_LDADD) $(LIBS) tools/hcitool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hcitool$(EXEEXT): $(tools_hcitool_OBJECTS) $(tools_hcitool_DEPENDENCIES) $(EXTRA_tools_hcitool_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/hcitool$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_hcitool_OBJECTS) $(tools_hcitool_LDADD) $(LIBS) tools/hid2hci.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/hid2hci$(EXEEXT): $(tools_hid2hci_OBJECTS) $(tools_hid2hci_DEPENDENCIES) $(EXTRA_tools_hid2hci_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/hid2hci$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_hid2hci_OBJECTS) $(tools_hid2hci_LDADD) $(LIBS) tools/l2ping.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/l2ping$(EXEEXT): $(tools_l2ping_OBJECTS) $(tools_l2ping_DEPENDENCIES) $(EXTRA_tools_l2ping_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/l2ping$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_l2ping_OBJECTS) $(tools_l2ping_LDADD) $(LIBS) tools/ppporc.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/ppporc$(EXEEXT): $(tools_ppporc_OBJECTS) $(tools_ppporc_DEPENDENCIES) $(EXTRA_tools_ppporc_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/ppporc$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_ppporc_OBJECTS) $(tools_ppporc_LDADD) $(LIBS) tools/rfcomm.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/parser.h: tools/parser.c @if test ! -f $@; then rm -f tools/parser.c; else :; fi @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) tools/parser.c; else :; fi tools/parser.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/lexer.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/kword.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) tools/rfcomm$(EXEEXT): $(tools_rfcomm_OBJECTS) $(tools_rfcomm_DEPENDENCIES) $(EXTRA_tools_rfcomm_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/rfcomm$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_rfcomm_OBJECTS) $(tools_rfcomm_LDADD) $(LIBS) tools/sdptool.$(OBJEXT): tools/$(am__dirstamp) \ tools/$(DEPDIR)/$(am__dirstamp) src/sdp-xml.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) tools/sdptool$(EXEEXT): $(tools_sdptool_OBJECTS) $(tools_sdptool_DEPENDENCIES) $(EXTRA_tools_sdptool_DEPENDENCIES) tools/$(am__dirstamp) @rm -f tools/sdptool$(EXEEXT) $(AM_V_CCLD)$(LINK) $(tools_sdptool_OBJECTS) $(tools_sdptool_LDADD) $(LIBS) unit/$(am__dirstamp): @$(MKDIR_P) unit @: > unit/$(am__dirstamp) unit/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) unit/$(DEPDIR) @: > unit/$(DEPDIR)/$(am__dirstamp) unit/unit_test_eir-test-eir.$(OBJEXT): unit/$(am__dirstamp) \ unit/$(DEPDIR)/$(am__dirstamp) src/unit_test_eir-eir.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) src/unit_test_eir-glib-helper.$(OBJEXT): src/$(am__dirstamp) \ src/$(DEPDIR)/$(am__dirstamp) unit/test-eir$(EXEEXT): $(unit_test_eir_OBJECTS) $(unit_test_eir_DEPENDENCIES) $(EXTRA_unit_test_eir_DEPENDENCIES) unit/$(am__dirstamp) @rm -f unit/test-eir$(EXEEXT) $(AM_V_CCLD)$(unit_test_eir_LINK) $(unit_test_eir_OBJECTS) $(unit_test_eir_LDADD) $(LIBS) install-dist_udevSCRIPTS: $(dist_udev_SCRIPTS) @$(NORMAL_INSTALL) test -z "$(udevdir)" || $(MKDIR_P) "$(DESTDIR)$(udevdir)" @list='$(dist_udev_SCRIPTS)'; test -n "$(udevdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n' \ -e 'h;s|.*|.|' \ -e 'p;x;s,.*/,,;$(transform)' | sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1; } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) { files[d] = files[d] " " $$1; \ if (++n[d] == $(am__install_max)) { \ print "f", d, files[d]; n[d] = 0; files[d] = "" } } \ else { print "f", d "/" $$4, $$1 } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(udevdir)$$dir'"; \ $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(udevdir)$$dir" || exit $$?; \ } \ ; done uninstall-dist_udevSCRIPTS: @$(NORMAL_UNINSTALL) @list='$(dist_udev_SCRIPTS)'; test -n "$(udevdir)" || exit 0; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 's,.*/,,;$(transform)'`; \ dir='$(DESTDIR)$(udevdir)'; $(am__uninstall_files_from_dir) mostlyclean-compile: -rm -f *.$(OBJEXT) -rm -f alert/bluetoothd-main.$(OBJEXT) -rm -f alert/bluetoothd-server.$(OBJEXT) -rm -f attrib/att.$(OBJEXT) -rm -f attrib/bluetoothd-att.$(OBJEXT) -rm -f attrib/bluetoothd-client.$(OBJEXT) -rm -f attrib/bluetoothd-gatt-service.$(OBJEXT) -rm -f attrib/bluetoothd-gatt.$(OBJEXT) -rm -f attrib/bluetoothd-gattrib.$(OBJEXT) -rm -f attrib/gatt.$(OBJEXT) -rm -f attrib/gattrib.$(OBJEXT) -rm -f attrib/gatttool.$(OBJEXT) -rm -f attrib/interactive.$(OBJEXT) -rm -f attrib/utils.$(OBJEXT) -rm -f audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.$(OBJEXT) -rm -f audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo -rm -f audio/audio_libasound_module_ctl_bluetooth_la-ipc.$(OBJEXT) -rm -f audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo -rm -f audio/audio_libasound_module_pcm_bluetooth_la-ipc.$(OBJEXT) -rm -f audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo -rm -f audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.$(OBJEXT) -rm -f audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo -rm -f audio/audio_libgstbluetooth_la-gsta2dpsink.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-gsta2dpsink.lo -rm -f audio/audio_libgstbluetooth_la-gstavdtpsink.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-gstavdtpsink.lo -rm -f audio/audio_libgstbluetooth_la-gstbluetooth.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-gstbluetooth.lo -rm -f audio/audio_libgstbluetooth_la-gstrtpsbcpay.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo -rm -f audio/audio_libgstbluetooth_la-gstsbcdec.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-gstsbcdec.lo -rm -f audio/audio_libgstbluetooth_la-gstsbcenc.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-gstsbcenc.lo -rm -f audio/audio_libgstbluetooth_la-gstsbcparse.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-gstsbcparse.lo -rm -f audio/audio_libgstbluetooth_la-gstsbcutil.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-gstsbcutil.lo -rm -f audio/audio_libgstbluetooth_la-ipc.$(OBJEXT) -rm -f audio/audio_libgstbluetooth_la-ipc.lo -rm -f audio/bluetoothd-a2dp.$(OBJEXT) -rm -f audio/bluetoothd-avctp.$(OBJEXT) -rm -f audio/bluetoothd-avdtp.$(OBJEXT) -rm -f audio/bluetoothd-avrcp.$(OBJEXT) -rm -f audio/bluetoothd-control.$(OBJEXT) -rm -f audio/bluetoothd-device.$(OBJEXT) -rm -f audio/bluetoothd-gateway.$(OBJEXT) -rm -f audio/bluetoothd-headset.$(OBJEXT) -rm -f audio/bluetoothd-ipc.$(OBJEXT) -rm -f audio/bluetoothd-main.$(OBJEXT) -rm -f audio/bluetoothd-manager.$(OBJEXT) -rm -f audio/bluetoothd-media.$(OBJEXT) -rm -f audio/bluetoothd-sink.$(OBJEXT) -rm -f audio/bluetoothd-source.$(OBJEXT) -rm -f audio/bluetoothd-telephony.$(OBJEXT) -rm -f audio/bluetoothd-transport.$(OBJEXT) -rm -f audio/bluetoothd-unix.$(OBJEXT) -rm -f audio/ipc.$(OBJEXT) -rm -f audio/telephony-dummy.$(OBJEXT) -rm -f audio/telephony-maemo5.$(OBJEXT) -rm -f audio/telephony-maemo6.$(OBJEXT) -rm -f audio/telephony-ofono.$(OBJEXT) -rm -f btio/bluetoothd-btio.$(OBJEXT) -rm -f btio/btio.$(OBJEXT) -rm -f compat/bnep.$(OBJEXT) -rm -f compat/dun.$(OBJEXT) -rm -f compat/dund.$(OBJEXT) -rm -f compat/fakehid.$(OBJEXT) -rm -f compat/hidd.$(OBJEXT) -rm -f compat/msdun.$(OBJEXT) -rm -f compat/pand.$(OBJEXT) -rm -f compat/sdp.$(OBJEXT) -rm -f cups/hcrp.$(OBJEXT) -rm -f cups/main.$(OBJEXT) -rm -f cups/sdp.$(OBJEXT) -rm -f cups/spp.$(OBJEXT) -rm -f deviceinfo/bluetoothd-deviceinfo.$(OBJEXT) -rm -f deviceinfo/bluetoothd-main.$(OBJEXT) -rm -f deviceinfo/bluetoothd-manager.$(OBJEXT) -rm -f emulator/btdev.$(OBJEXT) -rm -f emulator/main.$(OBJEXT) -rm -f emulator/server.$(OBJEXT) -rm -f emulator/vhci.$(OBJEXT) -rm -f gdbus/bluetoothd-mainloop.$(OBJEXT) -rm -f gdbus/bluetoothd-object.$(OBJEXT) -rm -f gdbus/bluetoothd-polkit.$(OBJEXT) -rm -f gdbus/bluetoothd-watch.$(OBJEXT) -rm -f gdbus/mainloop.$(OBJEXT) -rm -f gdbus/object.$(OBJEXT) -rm -f gdbus/polkit.$(OBJEXT) -rm -f gdbus/watch.$(OBJEXT) -rm -f health/bluetoothd-hdp.$(OBJEXT) -rm -f health/bluetoothd-hdp_main.$(OBJEXT) -rm -f health/bluetoothd-hdp_manager.$(OBJEXT) -rm -f health/bluetoothd-hdp_util.$(OBJEXT) -rm -f health/bluetoothd-mcap.$(OBJEXT) -rm -f health/bluetoothd-mcap_sync.$(OBJEXT) -rm -f input/bluetoothd-device.$(OBJEXT) -rm -f input/bluetoothd-fakehid.$(OBJEXT) -rm -f input/bluetoothd-main.$(OBJEXT) -rm -f input/bluetoothd-manager.$(OBJEXT) -rm -f input/bluetoothd-server.$(OBJEXT) -rm -f lib/bluetooth.$(OBJEXT) -rm -f lib/bluetooth.lo -rm -f lib/hci.$(OBJEXT) -rm -f lib/hci.lo -rm -f lib/sdp.$(OBJEXT) -rm -f lib/sdp.lo -rm -f lib/uuid.$(OBJEXT) -rm -f lib/uuid.lo -rm -f mgmt/main.$(OBJEXT) -rm -f monitor/btsnoop.$(OBJEXT) -rm -f monitor/control.$(OBJEXT) -rm -f monitor/hcidump.$(OBJEXT) -rm -f monitor/main.$(OBJEXT) -rm -f monitor/mainloop.$(OBJEXT) -rm -f monitor/packet.$(OBJEXT) -rm -f network/bluetoothd-common.$(OBJEXT) -rm -f network/bluetoothd-connection.$(OBJEXT) -rm -f network/bluetoothd-main.$(OBJEXT) -rm -f network/bluetoothd-manager.$(OBJEXT) -rm -f network/bluetoothd-server.$(OBJEXT) -rm -f plugins/bluetoothd-adaptername.$(OBJEXT) -rm -f plugins/bluetoothd-dbusoob.$(OBJEXT) -rm -f plugins/bluetoothd-formfactor.$(OBJEXT) -rm -f plugins/bluetoothd-gatt-example.$(OBJEXT) -rm -f plugins/bluetoothd-hal.$(OBJEXT) -rm -f plugins/bluetoothd-hciops.$(OBJEXT) -rm -f plugins/bluetoothd-maemo6.$(OBJEXT) -rm -f plugins/bluetoothd-mgmtops.$(OBJEXT) -rm -f plugins/bluetoothd-pnat.$(OBJEXT) -rm -f plugins/bluetoothd-service.$(OBJEXT) -rm -f plugins/bluetoothd-storage.$(OBJEXT) -rm -f plugins/bluetoothd-wiimote.$(OBJEXT) -rm -f plugins/plugins_external_dummy_la-external-dummy.$(OBJEXT) -rm -f plugins/plugins_external_dummy_la-external-dummy.lo -rm -f proximity/bluetoothd-immalert.$(OBJEXT) -rm -f proximity/bluetoothd-linkloss.$(OBJEXT) -rm -f proximity/bluetoothd-main.$(OBJEXT) -rm -f proximity/bluetoothd-manager.$(OBJEXT) -rm -f proximity/bluetoothd-monitor.$(OBJEXT) -rm -f proximity/bluetoothd-reporter.$(OBJEXT) -rm -f sap/bluetoothd-main.$(OBJEXT) -rm -f sap/bluetoothd-manager.$(OBJEXT) -rm -f sap/bluetoothd-sap.$(OBJEXT) -rm -f sap/bluetoothd-server.$(OBJEXT) -rm -f sap/sap-dummy.$(OBJEXT) -rm -f sap/sap-u8500.$(OBJEXT) -rm -f sbc/sbc_libsbc_la-sbc.$(OBJEXT) -rm -f sbc/sbc_libsbc_la-sbc.lo -rm -f sbc/sbc_libsbc_la-sbc_primitives.$(OBJEXT) -rm -f sbc/sbc_libsbc_la-sbc_primitives.lo -rm -f sbc/sbc_libsbc_la-sbc_primitives_armv6.$(OBJEXT) -rm -f sbc/sbc_libsbc_la-sbc_primitives_armv6.lo -rm -f sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.$(OBJEXT) -rm -f sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo -rm -f sbc/sbc_libsbc_la-sbc_primitives_mmx.$(OBJEXT) -rm -f sbc/sbc_libsbc_la-sbc_primitives_mmx.lo -rm -f sbc/sbc_libsbc_la-sbc_primitives_neon.$(OBJEXT) -rm -f sbc/sbc_libsbc_la-sbc_primitives_neon.lo -rm -f sbc/sbcdec.$(OBJEXT) -rm -f sbc/sbcenc.$(OBJEXT) -rm -f sbc/sbcinfo.$(OBJEXT) -rm -f sbc/sbctester.$(OBJEXT) -rm -f serial/bluetoothd-main.$(OBJEXT) -rm -f serial/bluetoothd-manager.$(OBJEXT) -rm -f serial/bluetoothd-port.$(OBJEXT) -rm -f serial/bluetoothd-proxy.$(OBJEXT) -rm -f src/bluetoothd-adapter.$(OBJEXT) -rm -f src/bluetoothd-agent.$(OBJEXT) -rm -f src/bluetoothd-attrib-server.$(OBJEXT) -rm -f src/bluetoothd-dbus-common.$(OBJEXT) -rm -f src/bluetoothd-device.$(OBJEXT) -rm -f src/bluetoothd-eir.$(OBJEXT) -rm -f src/bluetoothd-error.$(OBJEXT) -rm -f src/bluetoothd-event.$(OBJEXT) -rm -f src/bluetoothd-glib-helper.$(OBJEXT) -rm -f src/bluetoothd-log.$(OBJEXT) -rm -f src/bluetoothd-main.$(OBJEXT) -rm -f src/bluetoothd-manager.$(OBJEXT) -rm -f src/bluetoothd-oob.$(OBJEXT) -rm -f src/bluetoothd-oui.$(OBJEXT) -rm -f src/bluetoothd-plugin.$(OBJEXT) -rm -f src/bluetoothd-rfkill.$(OBJEXT) -rm -f src/bluetoothd-sdp-client.$(OBJEXT) -rm -f src/bluetoothd-sdp-xml.$(OBJEXT) -rm -f src/bluetoothd-sdpd-database.$(OBJEXT) -rm -f src/bluetoothd-sdpd-request.$(OBJEXT) -rm -f src/bluetoothd-sdpd-server.$(OBJEXT) -rm -f src/bluetoothd-sdpd-service.$(OBJEXT) -rm -f src/bluetoothd-storage.$(OBJEXT) -rm -f src/bluetoothd-textfile.$(OBJEXT) -rm -f src/glib-helper.$(OBJEXT) -rm -f src/log.$(OBJEXT) -rm -f src/oui.$(OBJEXT) -rm -f src/sdp-xml.$(OBJEXT) -rm -f src/textfile.$(OBJEXT) -rm -f src/unit_test_eir-eir.$(OBJEXT) -rm -f src/unit_test_eir-glib-helper.$(OBJEXT) -rm -f test/agent.$(OBJEXT) -rm -f test/attest.$(OBJEXT) -rm -f test/avtest.$(OBJEXT) -rm -f test/bdaddr.$(OBJEXT) -rm -f test/btiotest.$(OBJEXT) -rm -f test/gaptest.$(OBJEXT) -rm -f test/hciemu.$(OBJEXT) -rm -f test/hstest.$(OBJEXT) -rm -f test/ipctest.$(OBJEXT) -rm -f test/l2test.$(OBJEXT) -rm -f test/lmptest.$(OBJEXT) -rm -f test/mpris-player.$(OBJEXT) -rm -f test/rctest.$(OBJEXT) -rm -f test/scotest.$(OBJEXT) -rm -f test/sdptest.$(OBJEXT) -rm -f test/test-textfile.$(OBJEXT) -rm -f test/uuidtest.$(OBJEXT) -rm -f thermometer/bluetoothd-main.$(OBJEXT) -rm -f thermometer/bluetoothd-manager.$(OBJEXT) -rm -f thermometer/bluetoothd-thermometer.$(OBJEXT) -rm -f time/bluetoothd-main.$(OBJEXT) -rm -f time/bluetoothd-server.$(OBJEXT) -rm -f tools/avctrl.$(OBJEXT) -rm -f tools/avinfo.$(OBJEXT) -rm -f tools/bccmd.$(OBJEXT) -rm -f tools/ciptool.$(OBJEXT) -rm -f tools/csr.$(OBJEXT) -rm -f tools/csr_3wire.$(OBJEXT) -rm -f tools/csr_bcsp.$(OBJEXT) -rm -f tools/csr_h4.$(OBJEXT) -rm -f tools/csr_hci.$(OBJEXT) -rm -f tools/csr_usb.$(OBJEXT) -rm -f tools/dfu.$(OBJEXT) -rm -f tools/dfubabel.$(OBJEXT) -rm -f tools/dfutool.$(OBJEXT) -rm -f tools/hciattach.$(OBJEXT) -rm -f tools/hciattach_ath3k.$(OBJEXT) -rm -f tools/hciattach_intel.$(OBJEXT) -rm -f tools/hciattach_qualcomm.$(OBJEXT) -rm -f tools/hciattach_st.$(OBJEXT) -rm -f tools/hciattach_ti.$(OBJEXT) -rm -f tools/hciattach_tialt.$(OBJEXT) -rm -f tools/hciconfig.$(OBJEXT) -rm -f tools/hcieventmask.$(OBJEXT) -rm -f tools/hcisecfilter.$(OBJEXT) -rm -f tools/hcitool.$(OBJEXT) -rm -f tools/hid2hci.$(OBJEXT) -rm -f tools/kword.$(OBJEXT) -rm -f tools/l2ping.$(OBJEXT) -rm -f tools/lexer.$(OBJEXT) -rm -f tools/parser.$(OBJEXT) -rm -f tools/ppporc.$(OBJEXT) -rm -f tools/rfcomm.$(OBJEXT) -rm -f tools/sdptool.$(OBJEXT) -rm -f tools/ubcsp.$(OBJEXT) -rm -f unit/unit_test_eir-test-eir.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@alert/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@alert/$(DEPDIR)/bluetoothd-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/att.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-att.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt-service.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gattrib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/gatt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/gattrib.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/gatttool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/interactive.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ipc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-ipc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gsta2dpsink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstavdtpsink.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstbluetooth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstrtpsbcpay.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcdec.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcenc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcparse.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcutil.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-ipc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-a2dp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-avctp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-avdtp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-avrcp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-control.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-gateway.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-headset.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-ipc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-media.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-sink.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-source.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-telephony.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-transport.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-unix.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/ipc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/telephony-dummy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/telephony-maemo5.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/telephony-maemo6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/telephony-ofono.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/bluetoothd-btio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/btio.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/bnep.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/dun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/dund.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/fakehid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/hidd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/msdun.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/pand.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/sdp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cups/$(DEPDIR)/hcrp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cups/$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cups/$(DEPDIR)/sdp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@cups/$(DEPDIR)/spp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@deviceinfo/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@deviceinfo/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/btdev.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/vhci.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/bluetoothd-mainloop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/bluetoothd-object.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/bluetoothd-polkit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/bluetoothd-watch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/mainloop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/object.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/polkit.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/watch.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-hdp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-hdp_main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-hdp_manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-hdp_util.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-mcap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-mcap_sync.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-fakehid.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/bluetooth.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hci.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/sdp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/uuid.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@mgmt/$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/btsnoop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/control.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/hcidump.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/mainloop.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/packet.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-connection.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-adaptername.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-dbusoob.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-formfactor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-gatt-example.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-hal.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-hciops.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-maemo6.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-mgmtops.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-pnat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-service.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-storage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-wiimote.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-immalert.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-linkloss.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-monitor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-reporter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/bluetoothd-sap.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/bluetoothd-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/sap-dummy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/sap-u8500.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_iwmmxt.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbcdec.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbcenc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbcinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbctester.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@serial/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@serial/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@serial/$(DEPDIR)/bluetoothd-port.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@serial/$(DEPDIR)/bluetoothd-proxy.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-adapter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-agent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-attrib-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-dbus-common.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-device.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-eir.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-error.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-event.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-glib-helper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-oob.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-oui.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-plugin.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-rfkill.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdp-client.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdp-xml.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-database.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-request.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-service.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-storage.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-textfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/glib-helper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/log.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/oui.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdp-xml.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/textfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/unit_test_eir-eir.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/unit_test_eir-glib-helper.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/agent.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/attest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/avtest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/bdaddr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/btiotest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/gaptest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/hciemu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/hstest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ipctest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/l2test.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/lmptest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/mpris-player.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/rctest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/scotest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/sdptest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-textfile.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/uuidtest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@thermometer/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@thermometer/$(DEPDIR)/bluetoothd-manager.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@thermometer/$(DEPDIR)/bluetoothd-thermometer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@time/$(DEPDIR)/bluetoothd-main.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@time/$(DEPDIR)/bluetoothd-server.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avctrl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avinfo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bccmd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ciptool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_3wire.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_bcsp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_h4.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_hci.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_usb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/dfu.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/dfubabel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/dfutool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_ath3k.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_intel.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_qualcomm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_st.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_ti.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_tialt.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciconfig.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcieventmask.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcisecfilter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcitool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hid2hci.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/kword.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/l2ping.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/lexer.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/parser.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ppporc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rfcomm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/sdptool.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ubcsp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/unit_test_eir-test-eir.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ @am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: @am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ @am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ @am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo: audio/ctl_bluetooth.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo -MD -MP -MF audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.Tpo -c -o audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo `test -f 'audio/ctl_bluetooth.c' || echo '$(srcdir)/'`audio/ctl_bluetooth.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.Tpo audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/ctl_bluetooth.c' object='audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo `test -f 'audio/ctl_bluetooth.c' || echo '$(srcdir)/'`audio/ctl_bluetooth.c audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo: audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo -MD -MP -MF audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ipc.Tpo -c -o audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ipc.Tpo audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ipc.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/ipc.c' object='audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo: audio/pcm_bluetooth.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo -MD -MP -MF audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.Tpo -c -o audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo `test -f 'audio/pcm_bluetooth.c' || echo '$(srcdir)/'`audio/pcm_bluetooth.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.Tpo audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/pcm_bluetooth.c' object='audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo `test -f 'audio/pcm_bluetooth.c' || echo '$(srcdir)/'`audio/pcm_bluetooth.c audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo: audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo -MD -MP -MF audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-ipc.Tpo -c -o audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-ipc.Tpo audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-ipc.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/ipc.c' object='audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c audio/audio_libgstbluetooth_la-gstbluetooth.lo: audio/gstbluetooth.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstbluetooth.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstbluetooth.Tpo -c -o audio/audio_libgstbluetooth_la-gstbluetooth.lo `test -f 'audio/gstbluetooth.c' || echo '$(srcdir)/'`audio/gstbluetooth.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstbluetooth.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstbluetooth.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gstbluetooth.c' object='audio/audio_libgstbluetooth_la-gstbluetooth.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstbluetooth.lo `test -f 'audio/gstbluetooth.c' || echo '$(srcdir)/'`audio/gstbluetooth.c audio/audio_libgstbluetooth_la-gstsbcenc.lo: audio/gstsbcenc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstsbcenc.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcenc.Tpo -c -o audio/audio_libgstbluetooth_la-gstsbcenc.lo `test -f 'audio/gstsbcenc.c' || echo '$(srcdir)/'`audio/gstsbcenc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcenc.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcenc.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gstsbcenc.c' object='audio/audio_libgstbluetooth_la-gstsbcenc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstsbcenc.lo `test -f 'audio/gstsbcenc.c' || echo '$(srcdir)/'`audio/gstsbcenc.c audio/audio_libgstbluetooth_la-gstsbcdec.lo: audio/gstsbcdec.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstsbcdec.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcdec.Tpo -c -o audio/audio_libgstbluetooth_la-gstsbcdec.lo `test -f 'audio/gstsbcdec.c' || echo '$(srcdir)/'`audio/gstsbcdec.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcdec.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcdec.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gstsbcdec.c' object='audio/audio_libgstbluetooth_la-gstsbcdec.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstsbcdec.lo `test -f 'audio/gstsbcdec.c' || echo '$(srcdir)/'`audio/gstsbcdec.c audio/audio_libgstbluetooth_la-gstsbcparse.lo: audio/gstsbcparse.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstsbcparse.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcparse.Tpo -c -o audio/audio_libgstbluetooth_la-gstsbcparse.lo `test -f 'audio/gstsbcparse.c' || echo '$(srcdir)/'`audio/gstsbcparse.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcparse.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcparse.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gstsbcparse.c' object='audio/audio_libgstbluetooth_la-gstsbcparse.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstsbcparse.lo `test -f 'audio/gstsbcparse.c' || echo '$(srcdir)/'`audio/gstsbcparse.c audio/audio_libgstbluetooth_la-gstavdtpsink.lo: audio/gstavdtpsink.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstavdtpsink.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstavdtpsink.Tpo -c -o audio/audio_libgstbluetooth_la-gstavdtpsink.lo `test -f 'audio/gstavdtpsink.c' || echo '$(srcdir)/'`audio/gstavdtpsink.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstavdtpsink.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstavdtpsink.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gstavdtpsink.c' object='audio/audio_libgstbluetooth_la-gstavdtpsink.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstavdtpsink.lo `test -f 'audio/gstavdtpsink.c' || echo '$(srcdir)/'`audio/gstavdtpsink.c audio/audio_libgstbluetooth_la-gsta2dpsink.lo: audio/gsta2dpsink.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gsta2dpsink.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gsta2dpsink.Tpo -c -o audio/audio_libgstbluetooth_la-gsta2dpsink.lo `test -f 'audio/gsta2dpsink.c' || echo '$(srcdir)/'`audio/gsta2dpsink.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gsta2dpsink.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gsta2dpsink.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gsta2dpsink.c' object='audio/audio_libgstbluetooth_la-gsta2dpsink.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gsta2dpsink.lo `test -f 'audio/gsta2dpsink.c' || echo '$(srcdir)/'`audio/gsta2dpsink.c audio/audio_libgstbluetooth_la-gstsbcutil.lo: audio/gstsbcutil.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstsbcutil.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcutil.Tpo -c -o audio/audio_libgstbluetooth_la-gstsbcutil.lo `test -f 'audio/gstsbcutil.c' || echo '$(srcdir)/'`audio/gstsbcutil.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcutil.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcutil.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gstsbcutil.c' object='audio/audio_libgstbluetooth_la-gstsbcutil.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstsbcutil.lo `test -f 'audio/gstsbcutil.c' || echo '$(srcdir)/'`audio/gstsbcutil.c audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo: audio/gstrtpsbcpay.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstrtpsbcpay.Tpo -c -o audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo `test -f 'audio/gstrtpsbcpay.c' || echo '$(srcdir)/'`audio/gstrtpsbcpay.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstrtpsbcpay.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstrtpsbcpay.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gstrtpsbcpay.c' object='audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo `test -f 'audio/gstrtpsbcpay.c' || echo '$(srcdir)/'`audio/gstrtpsbcpay.c audio/audio_libgstbluetooth_la-ipc.lo: audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-ipc.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-ipc.Tpo -c -o audio/audio_libgstbluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-ipc.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-ipc.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/ipc.c' object='audio/audio_libgstbluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c plugins/plugins_external_dummy_la-external-dummy.lo: plugins/external-dummy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) -MT plugins/plugins_external_dummy_la-external-dummy.lo -MD -MP -MF plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Tpo -c -o plugins/plugins_external_dummy_la-external-dummy.lo `test -f 'plugins/external-dummy.c' || echo '$(srcdir)/'`plugins/external-dummy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Tpo plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/external-dummy.c' object='plugins/plugins_external_dummy_la-external-dummy.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) -c -o plugins/plugins_external_dummy_la-external-dummy.lo `test -f 'plugins/external-dummy.c' || echo '$(srcdir)/'`plugins/external-dummy.c sbc/sbc_libsbc_la-sbc.lo: sbc/sbc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Tpo -c -o sbc/sbc_libsbc_la-sbc.lo `test -f 'sbc/sbc.c' || echo '$(srcdir)/'`sbc/sbc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sbc/sbc.c' object='sbc/sbc_libsbc_la-sbc.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc.lo `test -f 'sbc/sbc.c' || echo '$(srcdir)/'`sbc/sbc.c sbc/sbc_libsbc_la-sbc_primitives.lo: sbc/sbc_primitives.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives.lo `test -f 'sbc/sbc_primitives.c' || echo '$(srcdir)/'`sbc/sbc_primitives.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sbc/sbc_primitives.c' object='sbc/sbc_libsbc_la-sbc_primitives.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives.lo `test -f 'sbc/sbc_primitives.c' || echo '$(srcdir)/'`sbc/sbc_primitives.c sbc/sbc_libsbc_la-sbc_primitives_mmx.lo: sbc/sbc_primitives_mmx.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_mmx.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_mmx.lo `test -f 'sbc/sbc_primitives_mmx.c' || echo '$(srcdir)/'`sbc/sbc_primitives_mmx.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sbc/sbc_primitives_mmx.c' object='sbc/sbc_libsbc_la-sbc_primitives_mmx.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_mmx.lo `test -f 'sbc/sbc_primitives_mmx.c' || echo '$(srcdir)/'`sbc/sbc_primitives_mmx.c sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo: sbc/sbc_primitives_iwmmxt.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_iwmmxt.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo `test -f 'sbc/sbc_primitives_iwmmxt.c' || echo '$(srcdir)/'`sbc/sbc_primitives_iwmmxt.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_iwmmxt.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_iwmmxt.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sbc/sbc_primitives_iwmmxt.c' object='sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo `test -f 'sbc/sbc_primitives_iwmmxt.c' || echo '$(srcdir)/'`sbc/sbc_primitives_iwmmxt.c sbc/sbc_libsbc_la-sbc_primitives_neon.lo: sbc/sbc_primitives_neon.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_neon.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_neon.lo `test -f 'sbc/sbc_primitives_neon.c' || echo '$(srcdir)/'`sbc/sbc_primitives_neon.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sbc/sbc_primitives_neon.c' object='sbc/sbc_libsbc_la-sbc_primitives_neon.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_neon.lo `test -f 'sbc/sbc_primitives_neon.c' || echo '$(srcdir)/'`sbc/sbc_primitives_neon.c sbc/sbc_libsbc_la-sbc_primitives_armv6.lo: sbc/sbc_primitives_armv6.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_armv6.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_armv6.lo `test -f 'sbc/sbc_primitives_armv6.c' || echo '$(srcdir)/'`sbc/sbc_primitives_armv6.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sbc/sbc_primitives_armv6.c' object='sbc/sbc_libsbc_la-sbc_primitives_armv6.lo' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_armv6.lo `test -f 'sbc/sbc_primitives_armv6.c' || echo '$(srcdir)/'`sbc/sbc_primitives_armv6.c gdbus/bluetoothd-mainloop.o: gdbus/mainloop.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-mainloop.o -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-mainloop.Tpo -c -o gdbus/bluetoothd-mainloop.o `test -f 'gdbus/mainloop.c' || echo '$(srcdir)/'`gdbus/mainloop.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-mainloop.Tpo gdbus/$(DEPDIR)/bluetoothd-mainloop.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdbus/mainloop.c' object='gdbus/bluetoothd-mainloop.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-mainloop.o `test -f 'gdbus/mainloop.c' || echo '$(srcdir)/'`gdbus/mainloop.c gdbus/bluetoothd-mainloop.obj: gdbus/mainloop.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-mainloop.obj -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-mainloop.Tpo -c -o gdbus/bluetoothd-mainloop.obj `if test -f 'gdbus/mainloop.c'; then $(CYGPATH_W) 'gdbus/mainloop.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/mainloop.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-mainloop.Tpo gdbus/$(DEPDIR)/bluetoothd-mainloop.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdbus/mainloop.c' object='gdbus/bluetoothd-mainloop.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-mainloop.obj `if test -f 'gdbus/mainloop.c'; then $(CYGPATH_W) 'gdbus/mainloop.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/mainloop.c'; fi` gdbus/bluetoothd-watch.o: gdbus/watch.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-watch.o -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-watch.Tpo -c -o gdbus/bluetoothd-watch.o `test -f 'gdbus/watch.c' || echo '$(srcdir)/'`gdbus/watch.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-watch.Tpo gdbus/$(DEPDIR)/bluetoothd-watch.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdbus/watch.c' object='gdbus/bluetoothd-watch.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-watch.o `test -f 'gdbus/watch.c' || echo '$(srcdir)/'`gdbus/watch.c gdbus/bluetoothd-watch.obj: gdbus/watch.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-watch.obj -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-watch.Tpo -c -o gdbus/bluetoothd-watch.obj `if test -f 'gdbus/watch.c'; then $(CYGPATH_W) 'gdbus/watch.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/watch.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-watch.Tpo gdbus/$(DEPDIR)/bluetoothd-watch.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdbus/watch.c' object='gdbus/bluetoothd-watch.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-watch.obj `if test -f 'gdbus/watch.c'; then $(CYGPATH_W) 'gdbus/watch.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/watch.c'; fi` gdbus/bluetoothd-object.o: gdbus/object.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-object.o -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-object.Tpo -c -o gdbus/bluetoothd-object.o `test -f 'gdbus/object.c' || echo '$(srcdir)/'`gdbus/object.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-object.Tpo gdbus/$(DEPDIR)/bluetoothd-object.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdbus/object.c' object='gdbus/bluetoothd-object.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-object.o `test -f 'gdbus/object.c' || echo '$(srcdir)/'`gdbus/object.c gdbus/bluetoothd-object.obj: gdbus/object.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-object.obj -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-object.Tpo -c -o gdbus/bluetoothd-object.obj `if test -f 'gdbus/object.c'; then $(CYGPATH_W) 'gdbus/object.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/object.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-object.Tpo gdbus/$(DEPDIR)/bluetoothd-object.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdbus/object.c' object='gdbus/bluetoothd-object.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-object.obj `if test -f 'gdbus/object.c'; then $(CYGPATH_W) 'gdbus/object.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/object.c'; fi` gdbus/bluetoothd-polkit.o: gdbus/polkit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-polkit.o -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-polkit.Tpo -c -o gdbus/bluetoothd-polkit.o `test -f 'gdbus/polkit.c' || echo '$(srcdir)/'`gdbus/polkit.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-polkit.Tpo gdbus/$(DEPDIR)/bluetoothd-polkit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdbus/polkit.c' object='gdbus/bluetoothd-polkit.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-polkit.o `test -f 'gdbus/polkit.c' || echo '$(srcdir)/'`gdbus/polkit.c gdbus/bluetoothd-polkit.obj: gdbus/polkit.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-polkit.obj -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-polkit.Tpo -c -o gdbus/bluetoothd-polkit.obj `if test -f 'gdbus/polkit.c'; then $(CYGPATH_W) 'gdbus/polkit.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/polkit.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-polkit.Tpo gdbus/$(DEPDIR)/bluetoothd-polkit.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gdbus/polkit.c' object='gdbus/bluetoothd-polkit.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-polkit.obj `if test -f 'gdbus/polkit.c'; then $(CYGPATH_W) 'gdbus/polkit.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/polkit.c'; fi` plugins/bluetoothd-pnat.o: plugins/pnat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-pnat.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-pnat.Tpo -c -o plugins/bluetoothd-pnat.o `test -f 'plugins/pnat.c' || echo '$(srcdir)/'`plugins/pnat.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-pnat.Tpo plugins/$(DEPDIR)/bluetoothd-pnat.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/pnat.c' object='plugins/bluetoothd-pnat.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-pnat.o `test -f 'plugins/pnat.c' || echo '$(srcdir)/'`plugins/pnat.c plugins/bluetoothd-pnat.obj: plugins/pnat.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-pnat.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-pnat.Tpo -c -o plugins/bluetoothd-pnat.obj `if test -f 'plugins/pnat.c'; then $(CYGPATH_W) 'plugins/pnat.c'; else $(CYGPATH_W) '$(srcdir)/plugins/pnat.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-pnat.Tpo plugins/$(DEPDIR)/bluetoothd-pnat.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/pnat.c' object='plugins/bluetoothd-pnat.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-pnat.obj `if test -f 'plugins/pnat.c'; then $(CYGPATH_W) 'plugins/pnat.c'; else $(CYGPATH_W) '$(srcdir)/plugins/pnat.c'; fi` audio/bluetoothd-main.o: audio/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-main.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-main.Tpo -c -o audio/bluetoothd-main.o `test -f 'audio/main.c' || echo '$(srcdir)/'`audio/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-main.Tpo audio/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/main.c' object='audio/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-main.o `test -f 'audio/main.c' || echo '$(srcdir)/'`audio/main.c audio/bluetoothd-main.obj: audio/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-main.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-main.Tpo -c -o audio/bluetoothd-main.obj `if test -f 'audio/main.c'; then $(CYGPATH_W) 'audio/main.c'; else $(CYGPATH_W) '$(srcdir)/audio/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-main.Tpo audio/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/main.c' object='audio/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-main.obj `if test -f 'audio/main.c'; then $(CYGPATH_W) 'audio/main.c'; else $(CYGPATH_W) '$(srcdir)/audio/main.c'; fi` audio/bluetoothd-manager.o: audio/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-manager.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-manager.Tpo -c -o audio/bluetoothd-manager.o `test -f 'audio/manager.c' || echo '$(srcdir)/'`audio/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-manager.Tpo audio/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/manager.c' object='audio/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-manager.o `test -f 'audio/manager.c' || echo '$(srcdir)/'`audio/manager.c audio/bluetoothd-manager.obj: audio/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-manager.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-manager.Tpo -c -o audio/bluetoothd-manager.obj `if test -f 'audio/manager.c'; then $(CYGPATH_W) 'audio/manager.c'; else $(CYGPATH_W) '$(srcdir)/audio/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-manager.Tpo audio/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/manager.c' object='audio/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-manager.obj `if test -f 'audio/manager.c'; then $(CYGPATH_W) 'audio/manager.c'; else $(CYGPATH_W) '$(srcdir)/audio/manager.c'; fi` audio/bluetoothd-gateway.o: audio/gateway.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-gateway.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-gateway.Tpo -c -o audio/bluetoothd-gateway.o `test -f 'audio/gateway.c' || echo '$(srcdir)/'`audio/gateway.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-gateway.Tpo audio/$(DEPDIR)/bluetoothd-gateway.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gateway.c' object='audio/bluetoothd-gateway.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-gateway.o `test -f 'audio/gateway.c' || echo '$(srcdir)/'`audio/gateway.c audio/bluetoothd-gateway.obj: audio/gateway.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-gateway.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-gateway.Tpo -c -o audio/bluetoothd-gateway.obj `if test -f 'audio/gateway.c'; then $(CYGPATH_W) 'audio/gateway.c'; else $(CYGPATH_W) '$(srcdir)/audio/gateway.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-gateway.Tpo audio/$(DEPDIR)/bluetoothd-gateway.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/gateway.c' object='audio/bluetoothd-gateway.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-gateway.obj `if test -f 'audio/gateway.c'; then $(CYGPATH_W) 'audio/gateway.c'; else $(CYGPATH_W) '$(srcdir)/audio/gateway.c'; fi` audio/bluetoothd-headset.o: audio/headset.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-headset.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-headset.Tpo -c -o audio/bluetoothd-headset.o `test -f 'audio/headset.c' || echo '$(srcdir)/'`audio/headset.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-headset.Tpo audio/$(DEPDIR)/bluetoothd-headset.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/headset.c' object='audio/bluetoothd-headset.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-headset.o `test -f 'audio/headset.c' || echo '$(srcdir)/'`audio/headset.c audio/bluetoothd-headset.obj: audio/headset.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-headset.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-headset.Tpo -c -o audio/bluetoothd-headset.obj `if test -f 'audio/headset.c'; then $(CYGPATH_W) 'audio/headset.c'; else $(CYGPATH_W) '$(srcdir)/audio/headset.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-headset.Tpo audio/$(DEPDIR)/bluetoothd-headset.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/headset.c' object='audio/bluetoothd-headset.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-headset.obj `if test -f 'audio/headset.c'; then $(CYGPATH_W) 'audio/headset.c'; else $(CYGPATH_W) '$(srcdir)/audio/headset.c'; fi` audio/bluetoothd-control.o: audio/control.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-control.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-control.Tpo -c -o audio/bluetoothd-control.o `test -f 'audio/control.c' || echo '$(srcdir)/'`audio/control.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-control.Tpo audio/$(DEPDIR)/bluetoothd-control.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/control.c' object='audio/bluetoothd-control.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-control.o `test -f 'audio/control.c' || echo '$(srcdir)/'`audio/control.c audio/bluetoothd-control.obj: audio/control.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-control.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-control.Tpo -c -o audio/bluetoothd-control.obj `if test -f 'audio/control.c'; then $(CYGPATH_W) 'audio/control.c'; else $(CYGPATH_W) '$(srcdir)/audio/control.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-control.Tpo audio/$(DEPDIR)/bluetoothd-control.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/control.c' object='audio/bluetoothd-control.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-control.obj `if test -f 'audio/control.c'; then $(CYGPATH_W) 'audio/control.c'; else $(CYGPATH_W) '$(srcdir)/audio/control.c'; fi` audio/bluetoothd-avctp.o: audio/avctp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avctp.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avctp.Tpo -c -o audio/bluetoothd-avctp.o `test -f 'audio/avctp.c' || echo '$(srcdir)/'`audio/avctp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avctp.Tpo audio/$(DEPDIR)/bluetoothd-avctp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/avctp.c' object='audio/bluetoothd-avctp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avctp.o `test -f 'audio/avctp.c' || echo '$(srcdir)/'`audio/avctp.c audio/bluetoothd-avctp.obj: audio/avctp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avctp.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avctp.Tpo -c -o audio/bluetoothd-avctp.obj `if test -f 'audio/avctp.c'; then $(CYGPATH_W) 'audio/avctp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avctp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avctp.Tpo audio/$(DEPDIR)/bluetoothd-avctp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/avctp.c' object='audio/bluetoothd-avctp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avctp.obj `if test -f 'audio/avctp.c'; then $(CYGPATH_W) 'audio/avctp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avctp.c'; fi` audio/bluetoothd-avrcp.o: audio/avrcp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avrcp.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avrcp.Tpo -c -o audio/bluetoothd-avrcp.o `test -f 'audio/avrcp.c' || echo '$(srcdir)/'`audio/avrcp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avrcp.Tpo audio/$(DEPDIR)/bluetoothd-avrcp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/avrcp.c' object='audio/bluetoothd-avrcp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avrcp.o `test -f 'audio/avrcp.c' || echo '$(srcdir)/'`audio/avrcp.c audio/bluetoothd-avrcp.obj: audio/avrcp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avrcp.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avrcp.Tpo -c -o audio/bluetoothd-avrcp.obj `if test -f 'audio/avrcp.c'; then $(CYGPATH_W) 'audio/avrcp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avrcp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avrcp.Tpo audio/$(DEPDIR)/bluetoothd-avrcp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/avrcp.c' object='audio/bluetoothd-avrcp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avrcp.obj `if test -f 'audio/avrcp.c'; then $(CYGPATH_W) 'audio/avrcp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avrcp.c'; fi` audio/bluetoothd-device.o: audio/device.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-device.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-device.Tpo -c -o audio/bluetoothd-device.o `test -f 'audio/device.c' || echo '$(srcdir)/'`audio/device.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-device.Tpo audio/$(DEPDIR)/bluetoothd-device.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/device.c' object='audio/bluetoothd-device.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-device.o `test -f 'audio/device.c' || echo '$(srcdir)/'`audio/device.c audio/bluetoothd-device.obj: audio/device.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-device.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-device.Tpo -c -o audio/bluetoothd-device.obj `if test -f 'audio/device.c'; then $(CYGPATH_W) 'audio/device.c'; else $(CYGPATH_W) '$(srcdir)/audio/device.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-device.Tpo audio/$(DEPDIR)/bluetoothd-device.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/device.c' object='audio/bluetoothd-device.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-device.obj `if test -f 'audio/device.c'; then $(CYGPATH_W) 'audio/device.c'; else $(CYGPATH_W) '$(srcdir)/audio/device.c'; fi` audio/bluetoothd-source.o: audio/source.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-source.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-source.Tpo -c -o audio/bluetoothd-source.o `test -f 'audio/source.c' || echo '$(srcdir)/'`audio/source.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-source.Tpo audio/$(DEPDIR)/bluetoothd-source.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/source.c' object='audio/bluetoothd-source.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-source.o `test -f 'audio/source.c' || echo '$(srcdir)/'`audio/source.c audio/bluetoothd-source.obj: audio/source.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-source.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-source.Tpo -c -o audio/bluetoothd-source.obj `if test -f 'audio/source.c'; then $(CYGPATH_W) 'audio/source.c'; else $(CYGPATH_W) '$(srcdir)/audio/source.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-source.Tpo audio/$(DEPDIR)/bluetoothd-source.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/source.c' object='audio/bluetoothd-source.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-source.obj `if test -f 'audio/source.c'; then $(CYGPATH_W) 'audio/source.c'; else $(CYGPATH_W) '$(srcdir)/audio/source.c'; fi` audio/bluetoothd-sink.o: audio/sink.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-sink.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-sink.Tpo -c -o audio/bluetoothd-sink.o `test -f 'audio/sink.c' || echo '$(srcdir)/'`audio/sink.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-sink.Tpo audio/$(DEPDIR)/bluetoothd-sink.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/sink.c' object='audio/bluetoothd-sink.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-sink.o `test -f 'audio/sink.c' || echo '$(srcdir)/'`audio/sink.c audio/bluetoothd-sink.obj: audio/sink.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-sink.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-sink.Tpo -c -o audio/bluetoothd-sink.obj `if test -f 'audio/sink.c'; then $(CYGPATH_W) 'audio/sink.c'; else $(CYGPATH_W) '$(srcdir)/audio/sink.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-sink.Tpo audio/$(DEPDIR)/bluetoothd-sink.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/sink.c' object='audio/bluetoothd-sink.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-sink.obj `if test -f 'audio/sink.c'; then $(CYGPATH_W) 'audio/sink.c'; else $(CYGPATH_W) '$(srcdir)/audio/sink.c'; fi` audio/bluetoothd-a2dp.o: audio/a2dp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-a2dp.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-a2dp.Tpo -c -o audio/bluetoothd-a2dp.o `test -f 'audio/a2dp.c' || echo '$(srcdir)/'`audio/a2dp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-a2dp.Tpo audio/$(DEPDIR)/bluetoothd-a2dp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/a2dp.c' object='audio/bluetoothd-a2dp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-a2dp.o `test -f 'audio/a2dp.c' || echo '$(srcdir)/'`audio/a2dp.c audio/bluetoothd-a2dp.obj: audio/a2dp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-a2dp.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-a2dp.Tpo -c -o audio/bluetoothd-a2dp.obj `if test -f 'audio/a2dp.c'; then $(CYGPATH_W) 'audio/a2dp.c'; else $(CYGPATH_W) '$(srcdir)/audio/a2dp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-a2dp.Tpo audio/$(DEPDIR)/bluetoothd-a2dp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/a2dp.c' object='audio/bluetoothd-a2dp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-a2dp.obj `if test -f 'audio/a2dp.c'; then $(CYGPATH_W) 'audio/a2dp.c'; else $(CYGPATH_W) '$(srcdir)/audio/a2dp.c'; fi` audio/bluetoothd-avdtp.o: audio/avdtp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avdtp.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avdtp.Tpo -c -o audio/bluetoothd-avdtp.o `test -f 'audio/avdtp.c' || echo '$(srcdir)/'`audio/avdtp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avdtp.Tpo audio/$(DEPDIR)/bluetoothd-avdtp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/avdtp.c' object='audio/bluetoothd-avdtp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avdtp.o `test -f 'audio/avdtp.c' || echo '$(srcdir)/'`audio/avdtp.c audio/bluetoothd-avdtp.obj: audio/avdtp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avdtp.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avdtp.Tpo -c -o audio/bluetoothd-avdtp.obj `if test -f 'audio/avdtp.c'; then $(CYGPATH_W) 'audio/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avdtp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avdtp.Tpo audio/$(DEPDIR)/bluetoothd-avdtp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/avdtp.c' object='audio/bluetoothd-avdtp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avdtp.obj `if test -f 'audio/avdtp.c'; then $(CYGPATH_W) 'audio/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avdtp.c'; fi` audio/bluetoothd-ipc.o: audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-ipc.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-ipc.Tpo -c -o audio/bluetoothd-ipc.o `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-ipc.Tpo audio/$(DEPDIR)/bluetoothd-ipc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/ipc.c' object='audio/bluetoothd-ipc.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-ipc.o `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c audio/bluetoothd-ipc.obj: audio/ipc.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-ipc.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-ipc.Tpo -c -o audio/bluetoothd-ipc.obj `if test -f 'audio/ipc.c'; then $(CYGPATH_W) 'audio/ipc.c'; else $(CYGPATH_W) '$(srcdir)/audio/ipc.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-ipc.Tpo audio/$(DEPDIR)/bluetoothd-ipc.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/ipc.c' object='audio/bluetoothd-ipc.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-ipc.obj `if test -f 'audio/ipc.c'; then $(CYGPATH_W) 'audio/ipc.c'; else $(CYGPATH_W) '$(srcdir)/audio/ipc.c'; fi` audio/bluetoothd-unix.o: audio/unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-unix.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-unix.Tpo -c -o audio/bluetoothd-unix.o `test -f 'audio/unix.c' || echo '$(srcdir)/'`audio/unix.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-unix.Tpo audio/$(DEPDIR)/bluetoothd-unix.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/unix.c' object='audio/bluetoothd-unix.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-unix.o `test -f 'audio/unix.c' || echo '$(srcdir)/'`audio/unix.c audio/bluetoothd-unix.obj: audio/unix.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-unix.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-unix.Tpo -c -o audio/bluetoothd-unix.obj `if test -f 'audio/unix.c'; then $(CYGPATH_W) 'audio/unix.c'; else $(CYGPATH_W) '$(srcdir)/audio/unix.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-unix.Tpo audio/$(DEPDIR)/bluetoothd-unix.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/unix.c' object='audio/bluetoothd-unix.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-unix.obj `if test -f 'audio/unix.c'; then $(CYGPATH_W) 'audio/unix.c'; else $(CYGPATH_W) '$(srcdir)/audio/unix.c'; fi` audio/bluetoothd-media.o: audio/media.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-media.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-media.Tpo -c -o audio/bluetoothd-media.o `test -f 'audio/media.c' || echo '$(srcdir)/'`audio/media.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-media.Tpo audio/$(DEPDIR)/bluetoothd-media.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/media.c' object='audio/bluetoothd-media.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-media.o `test -f 'audio/media.c' || echo '$(srcdir)/'`audio/media.c audio/bluetoothd-media.obj: audio/media.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-media.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-media.Tpo -c -o audio/bluetoothd-media.obj `if test -f 'audio/media.c'; then $(CYGPATH_W) 'audio/media.c'; else $(CYGPATH_W) '$(srcdir)/audio/media.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-media.Tpo audio/$(DEPDIR)/bluetoothd-media.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/media.c' object='audio/bluetoothd-media.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-media.obj `if test -f 'audio/media.c'; then $(CYGPATH_W) 'audio/media.c'; else $(CYGPATH_W) '$(srcdir)/audio/media.c'; fi` audio/bluetoothd-transport.o: audio/transport.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-transport.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-transport.Tpo -c -o audio/bluetoothd-transport.o `test -f 'audio/transport.c' || echo '$(srcdir)/'`audio/transport.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-transport.Tpo audio/$(DEPDIR)/bluetoothd-transport.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/transport.c' object='audio/bluetoothd-transport.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-transport.o `test -f 'audio/transport.c' || echo '$(srcdir)/'`audio/transport.c audio/bluetoothd-transport.obj: audio/transport.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-transport.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-transport.Tpo -c -o audio/bluetoothd-transport.obj `if test -f 'audio/transport.c'; then $(CYGPATH_W) 'audio/transport.c'; else $(CYGPATH_W) '$(srcdir)/audio/transport.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-transport.Tpo audio/$(DEPDIR)/bluetoothd-transport.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/transport.c' object='audio/bluetoothd-transport.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-transport.obj `if test -f 'audio/transport.c'; then $(CYGPATH_W) 'audio/transport.c'; else $(CYGPATH_W) '$(srcdir)/audio/transport.c'; fi` sap/bluetoothd-main.o: sap/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-main.o -MD -MP -MF sap/$(DEPDIR)/bluetoothd-main.Tpo -c -o sap/bluetoothd-main.o `test -f 'sap/main.c' || echo '$(srcdir)/'`sap/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-main.Tpo sap/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sap/main.c' object='sap/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-main.o `test -f 'sap/main.c' || echo '$(srcdir)/'`sap/main.c sap/bluetoothd-main.obj: sap/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-main.obj -MD -MP -MF sap/$(DEPDIR)/bluetoothd-main.Tpo -c -o sap/bluetoothd-main.obj `if test -f 'sap/main.c'; then $(CYGPATH_W) 'sap/main.c'; else $(CYGPATH_W) '$(srcdir)/sap/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-main.Tpo sap/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sap/main.c' object='sap/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-main.obj `if test -f 'sap/main.c'; then $(CYGPATH_W) 'sap/main.c'; else $(CYGPATH_W) '$(srcdir)/sap/main.c'; fi` sap/bluetoothd-manager.o: sap/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-manager.o -MD -MP -MF sap/$(DEPDIR)/bluetoothd-manager.Tpo -c -o sap/bluetoothd-manager.o `test -f 'sap/manager.c' || echo '$(srcdir)/'`sap/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-manager.Tpo sap/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sap/manager.c' object='sap/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-manager.o `test -f 'sap/manager.c' || echo '$(srcdir)/'`sap/manager.c sap/bluetoothd-manager.obj: sap/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-manager.obj -MD -MP -MF sap/$(DEPDIR)/bluetoothd-manager.Tpo -c -o sap/bluetoothd-manager.obj `if test -f 'sap/manager.c'; then $(CYGPATH_W) 'sap/manager.c'; else $(CYGPATH_W) '$(srcdir)/sap/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-manager.Tpo sap/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sap/manager.c' object='sap/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-manager.obj `if test -f 'sap/manager.c'; then $(CYGPATH_W) 'sap/manager.c'; else $(CYGPATH_W) '$(srcdir)/sap/manager.c'; fi` sap/bluetoothd-server.o: sap/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-server.o -MD -MP -MF sap/$(DEPDIR)/bluetoothd-server.Tpo -c -o sap/bluetoothd-server.o `test -f 'sap/server.c' || echo '$(srcdir)/'`sap/server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-server.Tpo sap/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sap/server.c' object='sap/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-server.o `test -f 'sap/server.c' || echo '$(srcdir)/'`sap/server.c sap/bluetoothd-server.obj: sap/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-server.obj -MD -MP -MF sap/$(DEPDIR)/bluetoothd-server.Tpo -c -o sap/bluetoothd-server.obj `if test -f 'sap/server.c'; then $(CYGPATH_W) 'sap/server.c'; else $(CYGPATH_W) '$(srcdir)/sap/server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-server.Tpo sap/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sap/server.c' object='sap/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-server.obj `if test -f 'sap/server.c'; then $(CYGPATH_W) 'sap/server.c'; else $(CYGPATH_W) '$(srcdir)/sap/server.c'; fi` input/bluetoothd-main.o: input/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-main.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-main.Tpo -c -o input/bluetoothd-main.o `test -f 'input/main.c' || echo '$(srcdir)/'`input/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-main.Tpo input/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/main.c' object='input/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-main.o `test -f 'input/main.c' || echo '$(srcdir)/'`input/main.c input/bluetoothd-main.obj: input/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-main.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-main.Tpo -c -o input/bluetoothd-main.obj `if test -f 'input/main.c'; then $(CYGPATH_W) 'input/main.c'; else $(CYGPATH_W) '$(srcdir)/input/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-main.Tpo input/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/main.c' object='input/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-main.obj `if test -f 'input/main.c'; then $(CYGPATH_W) 'input/main.c'; else $(CYGPATH_W) '$(srcdir)/input/main.c'; fi` input/bluetoothd-manager.o: input/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-manager.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-manager.Tpo -c -o input/bluetoothd-manager.o `test -f 'input/manager.c' || echo '$(srcdir)/'`input/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-manager.Tpo input/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/manager.c' object='input/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-manager.o `test -f 'input/manager.c' || echo '$(srcdir)/'`input/manager.c input/bluetoothd-manager.obj: input/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-manager.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-manager.Tpo -c -o input/bluetoothd-manager.obj `if test -f 'input/manager.c'; then $(CYGPATH_W) 'input/manager.c'; else $(CYGPATH_W) '$(srcdir)/input/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-manager.Tpo input/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/manager.c' object='input/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-manager.obj `if test -f 'input/manager.c'; then $(CYGPATH_W) 'input/manager.c'; else $(CYGPATH_W) '$(srcdir)/input/manager.c'; fi` input/bluetoothd-server.o: input/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-server.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-server.Tpo -c -o input/bluetoothd-server.o `test -f 'input/server.c' || echo '$(srcdir)/'`input/server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-server.Tpo input/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/server.c' object='input/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-server.o `test -f 'input/server.c' || echo '$(srcdir)/'`input/server.c input/bluetoothd-server.obj: input/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-server.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-server.Tpo -c -o input/bluetoothd-server.obj `if test -f 'input/server.c'; then $(CYGPATH_W) 'input/server.c'; else $(CYGPATH_W) '$(srcdir)/input/server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-server.Tpo input/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/server.c' object='input/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-server.obj `if test -f 'input/server.c'; then $(CYGPATH_W) 'input/server.c'; else $(CYGPATH_W) '$(srcdir)/input/server.c'; fi` input/bluetoothd-device.o: input/device.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-device.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-device.Tpo -c -o input/bluetoothd-device.o `test -f 'input/device.c' || echo '$(srcdir)/'`input/device.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-device.Tpo input/$(DEPDIR)/bluetoothd-device.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/device.c' object='input/bluetoothd-device.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-device.o `test -f 'input/device.c' || echo '$(srcdir)/'`input/device.c input/bluetoothd-device.obj: input/device.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-device.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-device.Tpo -c -o input/bluetoothd-device.obj `if test -f 'input/device.c'; then $(CYGPATH_W) 'input/device.c'; else $(CYGPATH_W) '$(srcdir)/input/device.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-device.Tpo input/$(DEPDIR)/bluetoothd-device.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/device.c' object='input/bluetoothd-device.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-device.obj `if test -f 'input/device.c'; then $(CYGPATH_W) 'input/device.c'; else $(CYGPATH_W) '$(srcdir)/input/device.c'; fi` input/bluetoothd-fakehid.o: input/fakehid.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-fakehid.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-fakehid.Tpo -c -o input/bluetoothd-fakehid.o `test -f 'input/fakehid.c' || echo '$(srcdir)/'`input/fakehid.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-fakehid.Tpo input/$(DEPDIR)/bluetoothd-fakehid.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/fakehid.c' object='input/bluetoothd-fakehid.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-fakehid.o `test -f 'input/fakehid.c' || echo '$(srcdir)/'`input/fakehid.c input/bluetoothd-fakehid.obj: input/fakehid.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-fakehid.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-fakehid.Tpo -c -o input/bluetoothd-fakehid.obj `if test -f 'input/fakehid.c'; then $(CYGPATH_W) 'input/fakehid.c'; else $(CYGPATH_W) '$(srcdir)/input/fakehid.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-fakehid.Tpo input/$(DEPDIR)/bluetoothd-fakehid.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='input/fakehid.c' object='input/bluetoothd-fakehid.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-fakehid.obj `if test -f 'input/fakehid.c'; then $(CYGPATH_W) 'input/fakehid.c'; else $(CYGPATH_W) '$(srcdir)/input/fakehid.c'; fi` serial/bluetoothd-main.o: serial/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-main.o -MD -MP -MF serial/$(DEPDIR)/bluetoothd-main.Tpo -c -o serial/bluetoothd-main.o `test -f 'serial/main.c' || echo '$(srcdir)/'`serial/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-main.Tpo serial/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial/main.c' object='serial/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-main.o `test -f 'serial/main.c' || echo '$(srcdir)/'`serial/main.c serial/bluetoothd-main.obj: serial/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-main.obj -MD -MP -MF serial/$(DEPDIR)/bluetoothd-main.Tpo -c -o serial/bluetoothd-main.obj `if test -f 'serial/main.c'; then $(CYGPATH_W) 'serial/main.c'; else $(CYGPATH_W) '$(srcdir)/serial/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-main.Tpo serial/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial/main.c' object='serial/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-main.obj `if test -f 'serial/main.c'; then $(CYGPATH_W) 'serial/main.c'; else $(CYGPATH_W) '$(srcdir)/serial/main.c'; fi` serial/bluetoothd-manager.o: serial/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-manager.o -MD -MP -MF serial/$(DEPDIR)/bluetoothd-manager.Tpo -c -o serial/bluetoothd-manager.o `test -f 'serial/manager.c' || echo '$(srcdir)/'`serial/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-manager.Tpo serial/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial/manager.c' object='serial/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-manager.o `test -f 'serial/manager.c' || echo '$(srcdir)/'`serial/manager.c serial/bluetoothd-manager.obj: serial/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-manager.obj -MD -MP -MF serial/$(DEPDIR)/bluetoothd-manager.Tpo -c -o serial/bluetoothd-manager.obj `if test -f 'serial/manager.c'; then $(CYGPATH_W) 'serial/manager.c'; else $(CYGPATH_W) '$(srcdir)/serial/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-manager.Tpo serial/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial/manager.c' object='serial/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-manager.obj `if test -f 'serial/manager.c'; then $(CYGPATH_W) 'serial/manager.c'; else $(CYGPATH_W) '$(srcdir)/serial/manager.c'; fi` serial/bluetoothd-proxy.o: serial/proxy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-proxy.o -MD -MP -MF serial/$(DEPDIR)/bluetoothd-proxy.Tpo -c -o serial/bluetoothd-proxy.o `test -f 'serial/proxy.c' || echo '$(srcdir)/'`serial/proxy.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-proxy.Tpo serial/$(DEPDIR)/bluetoothd-proxy.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial/proxy.c' object='serial/bluetoothd-proxy.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-proxy.o `test -f 'serial/proxy.c' || echo '$(srcdir)/'`serial/proxy.c serial/bluetoothd-proxy.obj: serial/proxy.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-proxy.obj -MD -MP -MF serial/$(DEPDIR)/bluetoothd-proxy.Tpo -c -o serial/bluetoothd-proxy.obj `if test -f 'serial/proxy.c'; then $(CYGPATH_W) 'serial/proxy.c'; else $(CYGPATH_W) '$(srcdir)/serial/proxy.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-proxy.Tpo serial/$(DEPDIR)/bluetoothd-proxy.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial/proxy.c' object='serial/bluetoothd-proxy.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-proxy.obj `if test -f 'serial/proxy.c'; then $(CYGPATH_W) 'serial/proxy.c'; else $(CYGPATH_W) '$(srcdir)/serial/proxy.c'; fi` serial/bluetoothd-port.o: serial/port.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-port.o -MD -MP -MF serial/$(DEPDIR)/bluetoothd-port.Tpo -c -o serial/bluetoothd-port.o `test -f 'serial/port.c' || echo '$(srcdir)/'`serial/port.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-port.Tpo serial/$(DEPDIR)/bluetoothd-port.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial/port.c' object='serial/bluetoothd-port.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-port.o `test -f 'serial/port.c' || echo '$(srcdir)/'`serial/port.c serial/bluetoothd-port.obj: serial/port.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-port.obj -MD -MP -MF serial/$(DEPDIR)/bluetoothd-port.Tpo -c -o serial/bluetoothd-port.obj `if test -f 'serial/port.c'; then $(CYGPATH_W) 'serial/port.c'; else $(CYGPATH_W) '$(srcdir)/serial/port.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-port.Tpo serial/$(DEPDIR)/bluetoothd-port.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='serial/port.c' object='serial/bluetoothd-port.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-port.obj `if test -f 'serial/port.c'; then $(CYGPATH_W) 'serial/port.c'; else $(CYGPATH_W) '$(srcdir)/serial/port.c'; fi` network/bluetoothd-main.o: network/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-main.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-main.Tpo -c -o network/bluetoothd-main.o `test -f 'network/main.c' || echo '$(srcdir)/'`network/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-main.Tpo network/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/main.c' object='network/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-main.o `test -f 'network/main.c' || echo '$(srcdir)/'`network/main.c network/bluetoothd-main.obj: network/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-main.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-main.Tpo -c -o network/bluetoothd-main.obj `if test -f 'network/main.c'; then $(CYGPATH_W) 'network/main.c'; else $(CYGPATH_W) '$(srcdir)/network/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-main.Tpo network/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/main.c' object='network/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-main.obj `if test -f 'network/main.c'; then $(CYGPATH_W) 'network/main.c'; else $(CYGPATH_W) '$(srcdir)/network/main.c'; fi` network/bluetoothd-manager.o: network/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-manager.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-manager.Tpo -c -o network/bluetoothd-manager.o `test -f 'network/manager.c' || echo '$(srcdir)/'`network/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-manager.Tpo network/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/manager.c' object='network/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-manager.o `test -f 'network/manager.c' || echo '$(srcdir)/'`network/manager.c network/bluetoothd-manager.obj: network/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-manager.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-manager.Tpo -c -o network/bluetoothd-manager.obj `if test -f 'network/manager.c'; then $(CYGPATH_W) 'network/manager.c'; else $(CYGPATH_W) '$(srcdir)/network/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-manager.Tpo network/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/manager.c' object='network/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-manager.obj `if test -f 'network/manager.c'; then $(CYGPATH_W) 'network/manager.c'; else $(CYGPATH_W) '$(srcdir)/network/manager.c'; fi` network/bluetoothd-common.o: network/common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-common.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-common.Tpo -c -o network/bluetoothd-common.o `test -f 'network/common.c' || echo '$(srcdir)/'`network/common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-common.Tpo network/$(DEPDIR)/bluetoothd-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/common.c' object='network/bluetoothd-common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-common.o `test -f 'network/common.c' || echo '$(srcdir)/'`network/common.c network/bluetoothd-common.obj: network/common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-common.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-common.Tpo -c -o network/bluetoothd-common.obj `if test -f 'network/common.c'; then $(CYGPATH_W) 'network/common.c'; else $(CYGPATH_W) '$(srcdir)/network/common.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-common.Tpo network/$(DEPDIR)/bluetoothd-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/common.c' object='network/bluetoothd-common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-common.obj `if test -f 'network/common.c'; then $(CYGPATH_W) 'network/common.c'; else $(CYGPATH_W) '$(srcdir)/network/common.c'; fi` network/bluetoothd-server.o: network/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-server.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-server.Tpo -c -o network/bluetoothd-server.o `test -f 'network/server.c' || echo '$(srcdir)/'`network/server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-server.Tpo network/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/server.c' object='network/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-server.o `test -f 'network/server.c' || echo '$(srcdir)/'`network/server.c network/bluetoothd-server.obj: network/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-server.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-server.Tpo -c -o network/bluetoothd-server.obj `if test -f 'network/server.c'; then $(CYGPATH_W) 'network/server.c'; else $(CYGPATH_W) '$(srcdir)/network/server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-server.Tpo network/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/server.c' object='network/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-server.obj `if test -f 'network/server.c'; then $(CYGPATH_W) 'network/server.c'; else $(CYGPATH_W) '$(srcdir)/network/server.c'; fi` network/bluetoothd-connection.o: network/connection.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-connection.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-connection.Tpo -c -o network/bluetoothd-connection.o `test -f 'network/connection.c' || echo '$(srcdir)/'`network/connection.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-connection.Tpo network/$(DEPDIR)/bluetoothd-connection.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/connection.c' object='network/bluetoothd-connection.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-connection.o `test -f 'network/connection.c' || echo '$(srcdir)/'`network/connection.c network/bluetoothd-connection.obj: network/connection.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-connection.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-connection.Tpo -c -o network/bluetoothd-connection.obj `if test -f 'network/connection.c'; then $(CYGPATH_W) 'network/connection.c'; else $(CYGPATH_W) '$(srcdir)/network/connection.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-connection.Tpo network/$(DEPDIR)/bluetoothd-connection.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='network/connection.c' object='network/bluetoothd-connection.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-connection.obj `if test -f 'network/connection.c'; then $(CYGPATH_W) 'network/connection.c'; else $(CYGPATH_W) '$(srcdir)/network/connection.c'; fi` plugins/bluetoothd-service.o: plugins/service.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-service.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-service.Tpo -c -o plugins/bluetoothd-service.o `test -f 'plugins/service.c' || echo '$(srcdir)/'`plugins/service.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-service.Tpo plugins/$(DEPDIR)/bluetoothd-service.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/service.c' object='plugins/bluetoothd-service.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-service.o `test -f 'plugins/service.c' || echo '$(srcdir)/'`plugins/service.c plugins/bluetoothd-service.obj: plugins/service.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-service.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-service.Tpo -c -o plugins/bluetoothd-service.obj `if test -f 'plugins/service.c'; then $(CYGPATH_W) 'plugins/service.c'; else $(CYGPATH_W) '$(srcdir)/plugins/service.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-service.Tpo plugins/$(DEPDIR)/bluetoothd-service.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/service.c' object='plugins/bluetoothd-service.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-service.obj `if test -f 'plugins/service.c'; then $(CYGPATH_W) 'plugins/service.c'; else $(CYGPATH_W) '$(srcdir)/plugins/service.c'; fi` health/bluetoothd-hdp_main.o: health/hdp_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_main.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_main.Tpo -c -o health/bluetoothd-hdp_main.o `test -f 'health/hdp_main.c' || echo '$(srcdir)/'`health/hdp_main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_main.Tpo health/$(DEPDIR)/bluetoothd-hdp_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/hdp_main.c' object='health/bluetoothd-hdp_main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_main.o `test -f 'health/hdp_main.c' || echo '$(srcdir)/'`health/hdp_main.c health/bluetoothd-hdp_main.obj: health/hdp_main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_main.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_main.Tpo -c -o health/bluetoothd-hdp_main.obj `if test -f 'health/hdp_main.c'; then $(CYGPATH_W) 'health/hdp_main.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_main.Tpo health/$(DEPDIR)/bluetoothd-hdp_main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/hdp_main.c' object='health/bluetoothd-hdp_main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_main.obj `if test -f 'health/hdp_main.c'; then $(CYGPATH_W) 'health/hdp_main.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_main.c'; fi` health/bluetoothd-hdp_manager.o: health/hdp_manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_manager.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo -c -o health/bluetoothd-hdp_manager.o `test -f 'health/hdp_manager.c' || echo '$(srcdir)/'`health/hdp_manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo health/$(DEPDIR)/bluetoothd-hdp_manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/hdp_manager.c' object='health/bluetoothd-hdp_manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_manager.o `test -f 'health/hdp_manager.c' || echo '$(srcdir)/'`health/hdp_manager.c health/bluetoothd-hdp_manager.obj: health/hdp_manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_manager.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo -c -o health/bluetoothd-hdp_manager.obj `if test -f 'health/hdp_manager.c'; then $(CYGPATH_W) 'health/hdp_manager.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo health/$(DEPDIR)/bluetoothd-hdp_manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/hdp_manager.c' object='health/bluetoothd-hdp_manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_manager.obj `if test -f 'health/hdp_manager.c'; then $(CYGPATH_W) 'health/hdp_manager.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_manager.c'; fi` health/bluetoothd-hdp.o: health/hdp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp.Tpo -c -o health/bluetoothd-hdp.o `test -f 'health/hdp.c' || echo '$(srcdir)/'`health/hdp.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp.Tpo health/$(DEPDIR)/bluetoothd-hdp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/hdp.c' object='health/bluetoothd-hdp.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp.o `test -f 'health/hdp.c' || echo '$(srcdir)/'`health/hdp.c health/bluetoothd-hdp.obj: health/hdp.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp.Tpo -c -o health/bluetoothd-hdp.obj `if test -f 'health/hdp.c'; then $(CYGPATH_W) 'health/hdp.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp.Tpo health/$(DEPDIR)/bluetoothd-hdp.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/hdp.c' object='health/bluetoothd-hdp.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp.obj `if test -f 'health/hdp.c'; then $(CYGPATH_W) 'health/hdp.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp.c'; fi` health/bluetoothd-hdp_util.o: health/hdp_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_util.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_util.Tpo -c -o health/bluetoothd-hdp_util.o `test -f 'health/hdp_util.c' || echo '$(srcdir)/'`health/hdp_util.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_util.Tpo health/$(DEPDIR)/bluetoothd-hdp_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/hdp_util.c' object='health/bluetoothd-hdp_util.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_util.o `test -f 'health/hdp_util.c' || echo '$(srcdir)/'`health/hdp_util.c health/bluetoothd-hdp_util.obj: health/hdp_util.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_util.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_util.Tpo -c -o health/bluetoothd-hdp_util.obj `if test -f 'health/hdp_util.c'; then $(CYGPATH_W) 'health/hdp_util.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_util.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_util.Tpo health/$(DEPDIR)/bluetoothd-hdp_util.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/hdp_util.c' object='health/bluetoothd-hdp_util.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_util.obj `if test -f 'health/hdp_util.c'; then $(CYGPATH_W) 'health/hdp_util.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_util.c'; fi` thermometer/bluetoothd-main.o: thermometer/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-main.o -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-main.Tpo -c -o thermometer/bluetoothd-main.o `test -f 'thermometer/main.c' || echo '$(srcdir)/'`thermometer/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-main.Tpo thermometer/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thermometer/main.c' object='thermometer/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-main.o `test -f 'thermometer/main.c' || echo '$(srcdir)/'`thermometer/main.c thermometer/bluetoothd-main.obj: thermometer/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-main.obj -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-main.Tpo -c -o thermometer/bluetoothd-main.obj `if test -f 'thermometer/main.c'; then $(CYGPATH_W) 'thermometer/main.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-main.Tpo thermometer/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thermometer/main.c' object='thermometer/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-main.obj `if test -f 'thermometer/main.c'; then $(CYGPATH_W) 'thermometer/main.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/main.c'; fi` thermometer/bluetoothd-manager.o: thermometer/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-manager.o -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-manager.Tpo -c -o thermometer/bluetoothd-manager.o `test -f 'thermometer/manager.c' || echo '$(srcdir)/'`thermometer/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-manager.Tpo thermometer/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thermometer/manager.c' object='thermometer/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-manager.o `test -f 'thermometer/manager.c' || echo '$(srcdir)/'`thermometer/manager.c thermometer/bluetoothd-manager.obj: thermometer/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-manager.obj -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-manager.Tpo -c -o thermometer/bluetoothd-manager.obj `if test -f 'thermometer/manager.c'; then $(CYGPATH_W) 'thermometer/manager.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-manager.Tpo thermometer/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thermometer/manager.c' object='thermometer/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-manager.obj `if test -f 'thermometer/manager.c'; then $(CYGPATH_W) 'thermometer/manager.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/manager.c'; fi` thermometer/bluetoothd-thermometer.o: thermometer/thermometer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-thermometer.o -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo -c -o thermometer/bluetoothd-thermometer.o `test -f 'thermometer/thermometer.c' || echo '$(srcdir)/'`thermometer/thermometer.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo thermometer/$(DEPDIR)/bluetoothd-thermometer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thermometer/thermometer.c' object='thermometer/bluetoothd-thermometer.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-thermometer.o `test -f 'thermometer/thermometer.c' || echo '$(srcdir)/'`thermometer/thermometer.c thermometer/bluetoothd-thermometer.obj: thermometer/thermometer.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-thermometer.obj -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo -c -o thermometer/bluetoothd-thermometer.obj `if test -f 'thermometer/thermometer.c'; then $(CYGPATH_W) 'thermometer/thermometer.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/thermometer.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo thermometer/$(DEPDIR)/bluetoothd-thermometer.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='thermometer/thermometer.c' object='thermometer/bluetoothd-thermometer.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-thermometer.obj `if test -f 'thermometer/thermometer.c'; then $(CYGPATH_W) 'thermometer/thermometer.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/thermometer.c'; fi` alert/bluetoothd-main.o: alert/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT alert/bluetoothd-main.o -MD -MP -MF alert/$(DEPDIR)/bluetoothd-main.Tpo -c -o alert/bluetoothd-main.o `test -f 'alert/main.c' || echo '$(srcdir)/'`alert/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) alert/$(DEPDIR)/bluetoothd-main.Tpo alert/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='alert/main.c' object='alert/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o alert/bluetoothd-main.o `test -f 'alert/main.c' || echo '$(srcdir)/'`alert/main.c alert/bluetoothd-main.obj: alert/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT alert/bluetoothd-main.obj -MD -MP -MF alert/$(DEPDIR)/bluetoothd-main.Tpo -c -o alert/bluetoothd-main.obj `if test -f 'alert/main.c'; then $(CYGPATH_W) 'alert/main.c'; else $(CYGPATH_W) '$(srcdir)/alert/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) alert/$(DEPDIR)/bluetoothd-main.Tpo alert/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='alert/main.c' object='alert/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o alert/bluetoothd-main.obj `if test -f 'alert/main.c'; then $(CYGPATH_W) 'alert/main.c'; else $(CYGPATH_W) '$(srcdir)/alert/main.c'; fi` alert/bluetoothd-server.o: alert/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT alert/bluetoothd-server.o -MD -MP -MF alert/$(DEPDIR)/bluetoothd-server.Tpo -c -o alert/bluetoothd-server.o `test -f 'alert/server.c' || echo '$(srcdir)/'`alert/server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) alert/$(DEPDIR)/bluetoothd-server.Tpo alert/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='alert/server.c' object='alert/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o alert/bluetoothd-server.o `test -f 'alert/server.c' || echo '$(srcdir)/'`alert/server.c alert/bluetoothd-server.obj: alert/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT alert/bluetoothd-server.obj -MD -MP -MF alert/$(DEPDIR)/bluetoothd-server.Tpo -c -o alert/bluetoothd-server.obj `if test -f 'alert/server.c'; then $(CYGPATH_W) 'alert/server.c'; else $(CYGPATH_W) '$(srcdir)/alert/server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) alert/$(DEPDIR)/bluetoothd-server.Tpo alert/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='alert/server.c' object='alert/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o alert/bluetoothd-server.obj `if test -f 'alert/server.c'; then $(CYGPATH_W) 'alert/server.c'; else $(CYGPATH_W) '$(srcdir)/alert/server.c'; fi` time/bluetoothd-main.o: time/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT time/bluetoothd-main.o -MD -MP -MF time/$(DEPDIR)/bluetoothd-main.Tpo -c -o time/bluetoothd-main.o `test -f 'time/main.c' || echo '$(srcdir)/'`time/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) time/$(DEPDIR)/bluetoothd-main.Tpo time/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='time/main.c' object='time/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o time/bluetoothd-main.o `test -f 'time/main.c' || echo '$(srcdir)/'`time/main.c time/bluetoothd-main.obj: time/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT time/bluetoothd-main.obj -MD -MP -MF time/$(DEPDIR)/bluetoothd-main.Tpo -c -o time/bluetoothd-main.obj `if test -f 'time/main.c'; then $(CYGPATH_W) 'time/main.c'; else $(CYGPATH_W) '$(srcdir)/time/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) time/$(DEPDIR)/bluetoothd-main.Tpo time/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='time/main.c' object='time/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o time/bluetoothd-main.obj `if test -f 'time/main.c'; then $(CYGPATH_W) 'time/main.c'; else $(CYGPATH_W) '$(srcdir)/time/main.c'; fi` time/bluetoothd-server.o: time/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT time/bluetoothd-server.o -MD -MP -MF time/$(DEPDIR)/bluetoothd-server.Tpo -c -o time/bluetoothd-server.o `test -f 'time/server.c' || echo '$(srcdir)/'`time/server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) time/$(DEPDIR)/bluetoothd-server.Tpo time/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='time/server.c' object='time/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o time/bluetoothd-server.o `test -f 'time/server.c' || echo '$(srcdir)/'`time/server.c time/bluetoothd-server.obj: time/server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT time/bluetoothd-server.obj -MD -MP -MF time/$(DEPDIR)/bluetoothd-server.Tpo -c -o time/bluetoothd-server.obj `if test -f 'time/server.c'; then $(CYGPATH_W) 'time/server.c'; else $(CYGPATH_W) '$(srcdir)/time/server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) time/$(DEPDIR)/bluetoothd-server.Tpo time/$(DEPDIR)/bluetoothd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='time/server.c' object='time/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o time/bluetoothd-server.obj `if test -f 'time/server.c'; then $(CYGPATH_W) 'time/server.c'; else $(CYGPATH_W) '$(srcdir)/time/server.c'; fi` plugins/bluetoothd-gatt-example.o: plugins/gatt-example.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-gatt-example.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo -c -o plugins/bluetoothd-gatt-example.o `test -f 'plugins/gatt-example.c' || echo '$(srcdir)/'`plugins/gatt-example.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo plugins/$(DEPDIR)/bluetoothd-gatt-example.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/gatt-example.c' object='plugins/bluetoothd-gatt-example.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-gatt-example.o `test -f 'plugins/gatt-example.c' || echo '$(srcdir)/'`plugins/gatt-example.c plugins/bluetoothd-gatt-example.obj: plugins/gatt-example.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-gatt-example.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo -c -o plugins/bluetoothd-gatt-example.obj `if test -f 'plugins/gatt-example.c'; then $(CYGPATH_W) 'plugins/gatt-example.c'; else $(CYGPATH_W) '$(srcdir)/plugins/gatt-example.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo plugins/$(DEPDIR)/bluetoothd-gatt-example.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/gatt-example.c' object='plugins/bluetoothd-gatt-example.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-gatt-example.obj `if test -f 'plugins/gatt-example.c'; then $(CYGPATH_W) 'plugins/gatt-example.c'; else $(CYGPATH_W) '$(srcdir)/plugins/gatt-example.c'; fi` proximity/bluetoothd-main.o: proximity/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-main.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-main.Tpo -c -o proximity/bluetoothd-main.o `test -f 'proximity/main.c' || echo '$(srcdir)/'`proximity/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-main.Tpo proximity/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/main.c' object='proximity/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-main.o `test -f 'proximity/main.c' || echo '$(srcdir)/'`proximity/main.c proximity/bluetoothd-main.obj: proximity/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-main.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-main.Tpo -c -o proximity/bluetoothd-main.obj `if test -f 'proximity/main.c'; then $(CYGPATH_W) 'proximity/main.c'; else $(CYGPATH_W) '$(srcdir)/proximity/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-main.Tpo proximity/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/main.c' object='proximity/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-main.obj `if test -f 'proximity/main.c'; then $(CYGPATH_W) 'proximity/main.c'; else $(CYGPATH_W) '$(srcdir)/proximity/main.c'; fi` proximity/bluetoothd-manager.o: proximity/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-manager.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-manager.Tpo -c -o proximity/bluetoothd-manager.o `test -f 'proximity/manager.c' || echo '$(srcdir)/'`proximity/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-manager.Tpo proximity/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/manager.c' object='proximity/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-manager.o `test -f 'proximity/manager.c' || echo '$(srcdir)/'`proximity/manager.c proximity/bluetoothd-manager.obj: proximity/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-manager.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-manager.Tpo -c -o proximity/bluetoothd-manager.obj `if test -f 'proximity/manager.c'; then $(CYGPATH_W) 'proximity/manager.c'; else $(CYGPATH_W) '$(srcdir)/proximity/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-manager.Tpo proximity/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/manager.c' object='proximity/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-manager.obj `if test -f 'proximity/manager.c'; then $(CYGPATH_W) 'proximity/manager.c'; else $(CYGPATH_W) '$(srcdir)/proximity/manager.c'; fi` proximity/bluetoothd-monitor.o: proximity/monitor.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-monitor.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-monitor.Tpo -c -o proximity/bluetoothd-monitor.o `test -f 'proximity/monitor.c' || echo '$(srcdir)/'`proximity/monitor.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-monitor.Tpo proximity/$(DEPDIR)/bluetoothd-monitor.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/monitor.c' object='proximity/bluetoothd-monitor.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-monitor.o `test -f 'proximity/monitor.c' || echo '$(srcdir)/'`proximity/monitor.c proximity/bluetoothd-monitor.obj: proximity/monitor.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-monitor.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-monitor.Tpo -c -o proximity/bluetoothd-monitor.obj `if test -f 'proximity/monitor.c'; then $(CYGPATH_W) 'proximity/monitor.c'; else $(CYGPATH_W) '$(srcdir)/proximity/monitor.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-monitor.Tpo proximity/$(DEPDIR)/bluetoothd-monitor.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/monitor.c' object='proximity/bluetoothd-monitor.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-monitor.obj `if test -f 'proximity/monitor.c'; then $(CYGPATH_W) 'proximity/monitor.c'; else $(CYGPATH_W) '$(srcdir)/proximity/monitor.c'; fi` proximity/bluetoothd-reporter.o: proximity/reporter.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-reporter.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-reporter.Tpo -c -o proximity/bluetoothd-reporter.o `test -f 'proximity/reporter.c' || echo '$(srcdir)/'`proximity/reporter.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-reporter.Tpo proximity/$(DEPDIR)/bluetoothd-reporter.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/reporter.c' object='proximity/bluetoothd-reporter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-reporter.o `test -f 'proximity/reporter.c' || echo '$(srcdir)/'`proximity/reporter.c proximity/bluetoothd-reporter.obj: proximity/reporter.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-reporter.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-reporter.Tpo -c -o proximity/bluetoothd-reporter.obj `if test -f 'proximity/reporter.c'; then $(CYGPATH_W) 'proximity/reporter.c'; else $(CYGPATH_W) '$(srcdir)/proximity/reporter.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-reporter.Tpo proximity/$(DEPDIR)/bluetoothd-reporter.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/reporter.c' object='proximity/bluetoothd-reporter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-reporter.obj `if test -f 'proximity/reporter.c'; then $(CYGPATH_W) 'proximity/reporter.c'; else $(CYGPATH_W) '$(srcdir)/proximity/reporter.c'; fi` proximity/bluetoothd-linkloss.o: proximity/linkloss.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-linkloss.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo -c -o proximity/bluetoothd-linkloss.o `test -f 'proximity/linkloss.c' || echo '$(srcdir)/'`proximity/linkloss.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo proximity/$(DEPDIR)/bluetoothd-linkloss.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/linkloss.c' object='proximity/bluetoothd-linkloss.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-linkloss.o `test -f 'proximity/linkloss.c' || echo '$(srcdir)/'`proximity/linkloss.c proximity/bluetoothd-linkloss.obj: proximity/linkloss.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-linkloss.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo -c -o proximity/bluetoothd-linkloss.obj `if test -f 'proximity/linkloss.c'; then $(CYGPATH_W) 'proximity/linkloss.c'; else $(CYGPATH_W) '$(srcdir)/proximity/linkloss.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo proximity/$(DEPDIR)/bluetoothd-linkloss.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/linkloss.c' object='proximity/bluetoothd-linkloss.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-linkloss.obj `if test -f 'proximity/linkloss.c'; then $(CYGPATH_W) 'proximity/linkloss.c'; else $(CYGPATH_W) '$(srcdir)/proximity/linkloss.c'; fi` proximity/bluetoothd-immalert.o: proximity/immalert.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-immalert.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-immalert.Tpo -c -o proximity/bluetoothd-immalert.o `test -f 'proximity/immalert.c' || echo '$(srcdir)/'`proximity/immalert.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-immalert.Tpo proximity/$(DEPDIR)/bluetoothd-immalert.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/immalert.c' object='proximity/bluetoothd-immalert.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-immalert.o `test -f 'proximity/immalert.c' || echo '$(srcdir)/'`proximity/immalert.c proximity/bluetoothd-immalert.obj: proximity/immalert.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-immalert.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-immalert.Tpo -c -o proximity/bluetoothd-immalert.obj `if test -f 'proximity/immalert.c'; then $(CYGPATH_W) 'proximity/immalert.c'; else $(CYGPATH_W) '$(srcdir)/proximity/immalert.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-immalert.Tpo proximity/$(DEPDIR)/bluetoothd-immalert.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='proximity/immalert.c' object='proximity/bluetoothd-immalert.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-immalert.obj `if test -f 'proximity/immalert.c'; then $(CYGPATH_W) 'proximity/immalert.c'; else $(CYGPATH_W) '$(srcdir)/proximity/immalert.c'; fi` deviceinfo/bluetoothd-main.o: deviceinfo/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-main.o -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-main.Tpo -c -o deviceinfo/bluetoothd-main.o `test -f 'deviceinfo/main.c' || echo '$(srcdir)/'`deviceinfo/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-main.Tpo deviceinfo/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='deviceinfo/main.c' object='deviceinfo/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-main.o `test -f 'deviceinfo/main.c' || echo '$(srcdir)/'`deviceinfo/main.c deviceinfo/bluetoothd-main.obj: deviceinfo/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-main.obj -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-main.Tpo -c -o deviceinfo/bluetoothd-main.obj `if test -f 'deviceinfo/main.c'; then $(CYGPATH_W) 'deviceinfo/main.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-main.Tpo deviceinfo/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='deviceinfo/main.c' object='deviceinfo/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-main.obj `if test -f 'deviceinfo/main.c'; then $(CYGPATH_W) 'deviceinfo/main.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/main.c'; fi` deviceinfo/bluetoothd-manager.o: deviceinfo/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-manager.o -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-manager.Tpo -c -o deviceinfo/bluetoothd-manager.o `test -f 'deviceinfo/manager.c' || echo '$(srcdir)/'`deviceinfo/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-manager.Tpo deviceinfo/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='deviceinfo/manager.c' object='deviceinfo/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-manager.o `test -f 'deviceinfo/manager.c' || echo '$(srcdir)/'`deviceinfo/manager.c deviceinfo/bluetoothd-manager.obj: deviceinfo/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-manager.obj -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-manager.Tpo -c -o deviceinfo/bluetoothd-manager.obj `if test -f 'deviceinfo/manager.c'; then $(CYGPATH_W) 'deviceinfo/manager.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-manager.Tpo deviceinfo/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='deviceinfo/manager.c' object='deviceinfo/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-manager.obj `if test -f 'deviceinfo/manager.c'; then $(CYGPATH_W) 'deviceinfo/manager.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/manager.c'; fi` deviceinfo/bluetoothd-deviceinfo.o: deviceinfo/deviceinfo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-deviceinfo.o -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo -c -o deviceinfo/bluetoothd-deviceinfo.o `test -f 'deviceinfo/deviceinfo.c' || echo '$(srcdir)/'`deviceinfo/deviceinfo.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='deviceinfo/deviceinfo.c' object='deviceinfo/bluetoothd-deviceinfo.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-deviceinfo.o `test -f 'deviceinfo/deviceinfo.c' || echo '$(srcdir)/'`deviceinfo/deviceinfo.c deviceinfo/bluetoothd-deviceinfo.obj: deviceinfo/deviceinfo.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-deviceinfo.obj -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo -c -o deviceinfo/bluetoothd-deviceinfo.obj `if test -f 'deviceinfo/deviceinfo.c'; then $(CYGPATH_W) 'deviceinfo/deviceinfo.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/deviceinfo.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='deviceinfo/deviceinfo.c' object='deviceinfo/bluetoothd-deviceinfo.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-deviceinfo.obj `if test -f 'deviceinfo/deviceinfo.c'; then $(CYGPATH_W) 'deviceinfo/deviceinfo.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/deviceinfo.c'; fi` plugins/bluetoothd-hciops.o: plugins/hciops.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hciops.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hciops.Tpo -c -o plugins/bluetoothd-hciops.o `test -f 'plugins/hciops.c' || echo '$(srcdir)/'`plugins/hciops.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hciops.Tpo plugins/$(DEPDIR)/bluetoothd-hciops.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/hciops.c' object='plugins/bluetoothd-hciops.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hciops.o `test -f 'plugins/hciops.c' || echo '$(srcdir)/'`plugins/hciops.c plugins/bluetoothd-hciops.obj: plugins/hciops.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hciops.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hciops.Tpo -c -o plugins/bluetoothd-hciops.obj `if test -f 'plugins/hciops.c'; then $(CYGPATH_W) 'plugins/hciops.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hciops.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hciops.Tpo plugins/$(DEPDIR)/bluetoothd-hciops.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/hciops.c' object='plugins/bluetoothd-hciops.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hciops.obj `if test -f 'plugins/hciops.c'; then $(CYGPATH_W) 'plugins/hciops.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hciops.c'; fi` plugins/bluetoothd-mgmtops.o: plugins/mgmtops.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-mgmtops.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-mgmtops.Tpo -c -o plugins/bluetoothd-mgmtops.o `test -f 'plugins/mgmtops.c' || echo '$(srcdir)/'`plugins/mgmtops.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-mgmtops.Tpo plugins/$(DEPDIR)/bluetoothd-mgmtops.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/mgmtops.c' object='plugins/bluetoothd-mgmtops.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-mgmtops.o `test -f 'plugins/mgmtops.c' || echo '$(srcdir)/'`plugins/mgmtops.c plugins/bluetoothd-mgmtops.obj: plugins/mgmtops.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-mgmtops.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-mgmtops.Tpo -c -o plugins/bluetoothd-mgmtops.obj `if test -f 'plugins/mgmtops.c'; then $(CYGPATH_W) 'plugins/mgmtops.c'; else $(CYGPATH_W) '$(srcdir)/plugins/mgmtops.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-mgmtops.Tpo plugins/$(DEPDIR)/bluetoothd-mgmtops.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/mgmtops.c' object='plugins/bluetoothd-mgmtops.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-mgmtops.obj `if test -f 'plugins/mgmtops.c'; then $(CYGPATH_W) 'plugins/mgmtops.c'; else $(CYGPATH_W) '$(srcdir)/plugins/mgmtops.c'; fi` plugins/bluetoothd-hal.o: plugins/hal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hal.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hal.Tpo -c -o plugins/bluetoothd-hal.o `test -f 'plugins/hal.c' || echo '$(srcdir)/'`plugins/hal.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hal.Tpo plugins/$(DEPDIR)/bluetoothd-hal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/hal.c' object='plugins/bluetoothd-hal.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hal.o `test -f 'plugins/hal.c' || echo '$(srcdir)/'`plugins/hal.c plugins/bluetoothd-hal.obj: plugins/hal.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hal.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hal.Tpo -c -o plugins/bluetoothd-hal.obj `if test -f 'plugins/hal.c'; then $(CYGPATH_W) 'plugins/hal.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hal.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hal.Tpo plugins/$(DEPDIR)/bluetoothd-hal.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/hal.c' object='plugins/bluetoothd-hal.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hal.obj `if test -f 'plugins/hal.c'; then $(CYGPATH_W) 'plugins/hal.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hal.c'; fi` plugins/bluetoothd-formfactor.o: plugins/formfactor.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-formfactor.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-formfactor.Tpo -c -o plugins/bluetoothd-formfactor.o `test -f 'plugins/formfactor.c' || echo '$(srcdir)/'`plugins/formfactor.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-formfactor.Tpo plugins/$(DEPDIR)/bluetoothd-formfactor.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/formfactor.c' object='plugins/bluetoothd-formfactor.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-formfactor.o `test -f 'plugins/formfactor.c' || echo '$(srcdir)/'`plugins/formfactor.c plugins/bluetoothd-formfactor.obj: plugins/formfactor.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-formfactor.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-formfactor.Tpo -c -o plugins/bluetoothd-formfactor.obj `if test -f 'plugins/formfactor.c'; then $(CYGPATH_W) 'plugins/formfactor.c'; else $(CYGPATH_W) '$(srcdir)/plugins/formfactor.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-formfactor.Tpo plugins/$(DEPDIR)/bluetoothd-formfactor.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/formfactor.c' object='plugins/bluetoothd-formfactor.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-formfactor.obj `if test -f 'plugins/formfactor.c'; then $(CYGPATH_W) 'plugins/formfactor.c'; else $(CYGPATH_W) '$(srcdir)/plugins/formfactor.c'; fi` plugins/bluetoothd-storage.o: plugins/storage.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-storage.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-storage.Tpo -c -o plugins/bluetoothd-storage.o `test -f 'plugins/storage.c' || echo '$(srcdir)/'`plugins/storage.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-storage.Tpo plugins/$(DEPDIR)/bluetoothd-storage.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/storage.c' object='plugins/bluetoothd-storage.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-storage.o `test -f 'plugins/storage.c' || echo '$(srcdir)/'`plugins/storage.c plugins/bluetoothd-storage.obj: plugins/storage.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-storage.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-storage.Tpo -c -o plugins/bluetoothd-storage.obj `if test -f 'plugins/storage.c'; then $(CYGPATH_W) 'plugins/storage.c'; else $(CYGPATH_W) '$(srcdir)/plugins/storage.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-storage.Tpo plugins/$(DEPDIR)/bluetoothd-storage.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/storage.c' object='plugins/bluetoothd-storage.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-storage.obj `if test -f 'plugins/storage.c'; then $(CYGPATH_W) 'plugins/storage.c'; else $(CYGPATH_W) '$(srcdir)/plugins/storage.c'; fi` plugins/bluetoothd-adaptername.o: plugins/adaptername.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-adaptername.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-adaptername.Tpo -c -o plugins/bluetoothd-adaptername.o `test -f 'plugins/adaptername.c' || echo '$(srcdir)/'`plugins/adaptername.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-adaptername.Tpo plugins/$(DEPDIR)/bluetoothd-adaptername.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/adaptername.c' object='plugins/bluetoothd-adaptername.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-adaptername.o `test -f 'plugins/adaptername.c' || echo '$(srcdir)/'`plugins/adaptername.c plugins/bluetoothd-adaptername.obj: plugins/adaptername.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-adaptername.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-adaptername.Tpo -c -o plugins/bluetoothd-adaptername.obj `if test -f 'plugins/adaptername.c'; then $(CYGPATH_W) 'plugins/adaptername.c'; else $(CYGPATH_W) '$(srcdir)/plugins/adaptername.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-adaptername.Tpo plugins/$(DEPDIR)/bluetoothd-adaptername.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/adaptername.c' object='plugins/bluetoothd-adaptername.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-adaptername.obj `if test -f 'plugins/adaptername.c'; then $(CYGPATH_W) 'plugins/adaptername.c'; else $(CYGPATH_W) '$(srcdir)/plugins/adaptername.c'; fi` plugins/bluetoothd-wiimote.o: plugins/wiimote.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-wiimote.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo -c -o plugins/bluetoothd-wiimote.o `test -f 'plugins/wiimote.c' || echo '$(srcdir)/'`plugins/wiimote.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo plugins/$(DEPDIR)/bluetoothd-wiimote.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/wiimote.c' object='plugins/bluetoothd-wiimote.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-wiimote.o `test -f 'plugins/wiimote.c' || echo '$(srcdir)/'`plugins/wiimote.c plugins/bluetoothd-wiimote.obj: plugins/wiimote.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-wiimote.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo -c -o plugins/bluetoothd-wiimote.obj `if test -f 'plugins/wiimote.c'; then $(CYGPATH_W) 'plugins/wiimote.c'; else $(CYGPATH_W) '$(srcdir)/plugins/wiimote.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo plugins/$(DEPDIR)/bluetoothd-wiimote.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/wiimote.c' object='plugins/bluetoothd-wiimote.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-wiimote.obj `if test -f 'plugins/wiimote.c'; then $(CYGPATH_W) 'plugins/wiimote.c'; else $(CYGPATH_W) '$(srcdir)/plugins/wiimote.c'; fi` plugins/bluetoothd-maemo6.o: plugins/maemo6.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-maemo6.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-maemo6.Tpo -c -o plugins/bluetoothd-maemo6.o `test -f 'plugins/maemo6.c' || echo '$(srcdir)/'`plugins/maemo6.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-maemo6.Tpo plugins/$(DEPDIR)/bluetoothd-maemo6.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/maemo6.c' object='plugins/bluetoothd-maemo6.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-maemo6.o `test -f 'plugins/maemo6.c' || echo '$(srcdir)/'`plugins/maemo6.c plugins/bluetoothd-maemo6.obj: plugins/maemo6.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-maemo6.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-maemo6.Tpo -c -o plugins/bluetoothd-maemo6.obj `if test -f 'plugins/maemo6.c'; then $(CYGPATH_W) 'plugins/maemo6.c'; else $(CYGPATH_W) '$(srcdir)/plugins/maemo6.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-maemo6.Tpo plugins/$(DEPDIR)/bluetoothd-maemo6.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/maemo6.c' object='plugins/bluetoothd-maemo6.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-maemo6.obj `if test -f 'plugins/maemo6.c'; then $(CYGPATH_W) 'plugins/maemo6.c'; else $(CYGPATH_W) '$(srcdir)/plugins/maemo6.c'; fi` plugins/bluetoothd-dbusoob.o: plugins/dbusoob.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-dbusoob.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-dbusoob.Tpo -c -o plugins/bluetoothd-dbusoob.o `test -f 'plugins/dbusoob.c' || echo '$(srcdir)/'`plugins/dbusoob.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-dbusoob.Tpo plugins/$(DEPDIR)/bluetoothd-dbusoob.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/dbusoob.c' object='plugins/bluetoothd-dbusoob.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-dbusoob.o `test -f 'plugins/dbusoob.c' || echo '$(srcdir)/'`plugins/dbusoob.c plugins/bluetoothd-dbusoob.obj: plugins/dbusoob.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-dbusoob.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-dbusoob.Tpo -c -o plugins/bluetoothd-dbusoob.obj `if test -f 'plugins/dbusoob.c'; then $(CYGPATH_W) 'plugins/dbusoob.c'; else $(CYGPATH_W) '$(srcdir)/plugins/dbusoob.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-dbusoob.Tpo plugins/$(DEPDIR)/bluetoothd-dbusoob.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plugins/dbusoob.c' object='plugins/bluetoothd-dbusoob.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-dbusoob.obj `if test -f 'plugins/dbusoob.c'; then $(CYGPATH_W) 'plugins/dbusoob.c'; else $(CYGPATH_W) '$(srcdir)/plugins/dbusoob.c'; fi` attrib/bluetoothd-att.o: attrib/att.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-att.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-att.Tpo -c -o attrib/bluetoothd-att.o `test -f 'attrib/att.c' || echo '$(srcdir)/'`attrib/att.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-att.Tpo attrib/$(DEPDIR)/bluetoothd-att.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/att.c' object='attrib/bluetoothd-att.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-att.o `test -f 'attrib/att.c' || echo '$(srcdir)/'`attrib/att.c attrib/bluetoothd-att.obj: attrib/att.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-att.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-att.Tpo -c -o attrib/bluetoothd-att.obj `if test -f 'attrib/att.c'; then $(CYGPATH_W) 'attrib/att.c'; else $(CYGPATH_W) '$(srcdir)/attrib/att.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-att.Tpo attrib/$(DEPDIR)/bluetoothd-att.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/att.c' object='attrib/bluetoothd-att.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-att.obj `if test -f 'attrib/att.c'; then $(CYGPATH_W) 'attrib/att.c'; else $(CYGPATH_W) '$(srcdir)/attrib/att.c'; fi` attrib/bluetoothd-gatt.o: attrib/gatt.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt.Tpo -c -o attrib/bluetoothd-gatt.o `test -f 'attrib/gatt.c' || echo '$(srcdir)/'`attrib/gatt.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt.Tpo attrib/$(DEPDIR)/bluetoothd-gatt.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gatt.c' object='attrib/bluetoothd-gatt.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gatt.o `test -f 'attrib/gatt.c' || echo '$(srcdir)/'`attrib/gatt.c attrib/bluetoothd-gatt.obj: attrib/gatt.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt.Tpo -c -o attrib/bluetoothd-gatt.obj `if test -f 'attrib/gatt.c'; then $(CYGPATH_W) 'attrib/gatt.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gatt.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt.Tpo attrib/$(DEPDIR)/bluetoothd-gatt.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gatt.c' object='attrib/bluetoothd-gatt.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gatt.obj `if test -f 'attrib/gatt.c'; then $(CYGPATH_W) 'attrib/gatt.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gatt.c'; fi` attrib/bluetoothd-gattrib.o: attrib/gattrib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gattrib.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gattrib.Tpo -c -o attrib/bluetoothd-gattrib.o `test -f 'attrib/gattrib.c' || echo '$(srcdir)/'`attrib/gattrib.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gattrib.Tpo attrib/$(DEPDIR)/bluetoothd-gattrib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gattrib.c' object='attrib/bluetoothd-gattrib.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gattrib.o `test -f 'attrib/gattrib.c' || echo '$(srcdir)/'`attrib/gattrib.c attrib/bluetoothd-gattrib.obj: attrib/gattrib.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gattrib.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gattrib.Tpo -c -o attrib/bluetoothd-gattrib.obj `if test -f 'attrib/gattrib.c'; then $(CYGPATH_W) 'attrib/gattrib.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gattrib.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gattrib.Tpo attrib/$(DEPDIR)/bluetoothd-gattrib.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gattrib.c' object='attrib/bluetoothd-gattrib.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gattrib.obj `if test -f 'attrib/gattrib.c'; then $(CYGPATH_W) 'attrib/gattrib.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gattrib.c'; fi` attrib/bluetoothd-client.o: attrib/client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-client.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-client.Tpo -c -o attrib/bluetoothd-client.o `test -f 'attrib/client.c' || echo '$(srcdir)/'`attrib/client.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-client.Tpo attrib/$(DEPDIR)/bluetoothd-client.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/client.c' object='attrib/bluetoothd-client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-client.o `test -f 'attrib/client.c' || echo '$(srcdir)/'`attrib/client.c attrib/bluetoothd-client.obj: attrib/client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-client.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-client.Tpo -c -o attrib/bluetoothd-client.obj `if test -f 'attrib/client.c'; then $(CYGPATH_W) 'attrib/client.c'; else $(CYGPATH_W) '$(srcdir)/attrib/client.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-client.Tpo attrib/$(DEPDIR)/bluetoothd-client.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/client.c' object='attrib/bluetoothd-client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-client.obj `if test -f 'attrib/client.c'; then $(CYGPATH_W) 'attrib/client.c'; else $(CYGPATH_W) '$(srcdir)/attrib/client.c'; fi` attrib/bluetoothd-gatt-service.o: attrib/gatt-service.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt-service.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo -c -o attrib/bluetoothd-gatt-service.o `test -f 'attrib/gatt-service.c' || echo '$(srcdir)/'`attrib/gatt-service.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo attrib/$(DEPDIR)/bluetoothd-gatt-service.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gatt-service.c' object='attrib/bluetoothd-gatt-service.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gatt-service.o `test -f 'attrib/gatt-service.c' || echo '$(srcdir)/'`attrib/gatt-service.c attrib/bluetoothd-gatt-service.obj: attrib/gatt-service.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt-service.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo -c -o attrib/bluetoothd-gatt-service.obj `if test -f 'attrib/gatt-service.c'; then $(CYGPATH_W) 'attrib/gatt-service.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gatt-service.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo attrib/$(DEPDIR)/bluetoothd-gatt-service.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='attrib/gatt-service.c' object='attrib/bluetoothd-gatt-service.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gatt-service.obj `if test -f 'attrib/gatt-service.c'; then $(CYGPATH_W) 'attrib/gatt-service.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gatt-service.c'; fi` btio/bluetoothd-btio.o: btio/btio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT btio/bluetoothd-btio.o -MD -MP -MF btio/$(DEPDIR)/bluetoothd-btio.Tpo -c -o btio/bluetoothd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/bluetoothd-btio.Tpo btio/$(DEPDIR)/bluetoothd-btio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btio/btio.c' object='btio/bluetoothd-btio.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o btio/bluetoothd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c btio/bluetoothd-btio.obj: btio/btio.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT btio/bluetoothd-btio.obj -MD -MP -MF btio/$(DEPDIR)/bluetoothd-btio.Tpo -c -o btio/bluetoothd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) btio/$(DEPDIR)/bluetoothd-btio.Tpo btio/$(DEPDIR)/bluetoothd-btio.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='btio/btio.c' object='btio/bluetoothd-btio.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o btio/bluetoothd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi` health/bluetoothd-mcap.o: health/mcap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-mcap.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-mcap.Tpo -c -o health/bluetoothd-mcap.o `test -f 'health/mcap.c' || echo '$(srcdir)/'`health/mcap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-mcap.Tpo health/$(DEPDIR)/bluetoothd-mcap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/mcap.c' object='health/bluetoothd-mcap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-mcap.o `test -f 'health/mcap.c' || echo '$(srcdir)/'`health/mcap.c health/bluetoothd-mcap.obj: health/mcap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-mcap.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-mcap.Tpo -c -o health/bluetoothd-mcap.obj `if test -f 'health/mcap.c'; then $(CYGPATH_W) 'health/mcap.c'; else $(CYGPATH_W) '$(srcdir)/health/mcap.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-mcap.Tpo health/$(DEPDIR)/bluetoothd-mcap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/mcap.c' object='health/bluetoothd-mcap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-mcap.obj `if test -f 'health/mcap.c'; then $(CYGPATH_W) 'health/mcap.c'; else $(CYGPATH_W) '$(srcdir)/health/mcap.c'; fi` health/bluetoothd-mcap_sync.o: health/mcap_sync.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-mcap_sync.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo -c -o health/bluetoothd-mcap_sync.o `test -f 'health/mcap_sync.c' || echo '$(srcdir)/'`health/mcap_sync.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo health/$(DEPDIR)/bluetoothd-mcap_sync.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/mcap_sync.c' object='health/bluetoothd-mcap_sync.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-mcap_sync.o `test -f 'health/mcap_sync.c' || echo '$(srcdir)/'`health/mcap_sync.c health/bluetoothd-mcap_sync.obj: health/mcap_sync.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-mcap_sync.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo -c -o health/bluetoothd-mcap_sync.obj `if test -f 'health/mcap_sync.c'; then $(CYGPATH_W) 'health/mcap_sync.c'; else $(CYGPATH_W) '$(srcdir)/health/mcap_sync.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo health/$(DEPDIR)/bluetoothd-mcap_sync.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='health/mcap_sync.c' object='health/bluetoothd-mcap_sync.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-mcap_sync.obj `if test -f 'health/mcap_sync.c'; then $(CYGPATH_W) 'health/mcap_sync.c'; else $(CYGPATH_W) '$(srcdir)/health/mcap_sync.c'; fi` src/bluetoothd-main.o: src/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-main.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-main.Tpo -c -o src/bluetoothd-main.o `test -f 'src/main.c' || echo '$(srcdir)/'`src/main.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-main.Tpo src/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/main.c' object='src/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-main.o `test -f 'src/main.c' || echo '$(srcdir)/'`src/main.c src/bluetoothd-main.obj: src/main.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-main.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-main.Tpo -c -o src/bluetoothd-main.obj `if test -f 'src/main.c'; then $(CYGPATH_W) 'src/main.c'; else $(CYGPATH_W) '$(srcdir)/src/main.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-main.Tpo src/$(DEPDIR)/bluetoothd-main.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/main.c' object='src/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-main.obj `if test -f 'src/main.c'; then $(CYGPATH_W) 'src/main.c'; else $(CYGPATH_W) '$(srcdir)/src/main.c'; fi` src/bluetoothd-log.o: src/log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-log.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-log.Tpo -c -o src/bluetoothd-log.o `test -f 'src/log.c' || echo '$(srcdir)/'`src/log.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-log.Tpo src/$(DEPDIR)/bluetoothd-log.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/log.c' object='src/bluetoothd-log.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-log.o `test -f 'src/log.c' || echo '$(srcdir)/'`src/log.c src/bluetoothd-log.obj: src/log.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-log.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-log.Tpo -c -o src/bluetoothd-log.obj `if test -f 'src/log.c'; then $(CYGPATH_W) 'src/log.c'; else $(CYGPATH_W) '$(srcdir)/src/log.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-log.Tpo src/$(DEPDIR)/bluetoothd-log.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/log.c' object='src/bluetoothd-log.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-log.obj `if test -f 'src/log.c'; then $(CYGPATH_W) 'src/log.c'; else $(CYGPATH_W) '$(srcdir)/src/log.c'; fi` src/bluetoothd-rfkill.o: src/rfkill.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-rfkill.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-rfkill.Tpo -c -o src/bluetoothd-rfkill.o `test -f 'src/rfkill.c' || echo '$(srcdir)/'`src/rfkill.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-rfkill.Tpo src/$(DEPDIR)/bluetoothd-rfkill.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/rfkill.c' object='src/bluetoothd-rfkill.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-rfkill.o `test -f 'src/rfkill.c' || echo '$(srcdir)/'`src/rfkill.c src/bluetoothd-rfkill.obj: src/rfkill.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-rfkill.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-rfkill.Tpo -c -o src/bluetoothd-rfkill.obj `if test -f 'src/rfkill.c'; then $(CYGPATH_W) 'src/rfkill.c'; else $(CYGPATH_W) '$(srcdir)/src/rfkill.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-rfkill.Tpo src/$(DEPDIR)/bluetoothd-rfkill.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/rfkill.c' object='src/bluetoothd-rfkill.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-rfkill.obj `if test -f 'src/rfkill.c'; then $(CYGPATH_W) 'src/rfkill.c'; else $(CYGPATH_W) '$(srcdir)/src/rfkill.c'; fi` src/bluetoothd-sdpd-server.o: src/sdpd-server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-server.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-server.Tpo -c -o src/bluetoothd-sdpd-server.o `test -f 'src/sdpd-server.c' || echo '$(srcdir)/'`src/sdpd-server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-server.Tpo src/$(DEPDIR)/bluetoothd-sdpd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-server.c' object='src/bluetoothd-sdpd-server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-server.o `test -f 'src/sdpd-server.c' || echo '$(srcdir)/'`src/sdpd-server.c src/bluetoothd-sdpd-server.obj: src/sdpd-server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-server.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-server.Tpo -c -o src/bluetoothd-sdpd-server.obj `if test -f 'src/sdpd-server.c'; then $(CYGPATH_W) 'src/sdpd-server.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-server.Tpo src/$(DEPDIR)/bluetoothd-sdpd-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-server.c' object='src/bluetoothd-sdpd-server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-server.obj `if test -f 'src/sdpd-server.c'; then $(CYGPATH_W) 'src/sdpd-server.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-server.c'; fi` src/bluetoothd-sdpd-request.o: src/sdpd-request.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-request.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-request.Tpo -c -o src/bluetoothd-sdpd-request.o `test -f 'src/sdpd-request.c' || echo '$(srcdir)/'`src/sdpd-request.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-request.Tpo src/$(DEPDIR)/bluetoothd-sdpd-request.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-request.c' object='src/bluetoothd-sdpd-request.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-request.o `test -f 'src/sdpd-request.c' || echo '$(srcdir)/'`src/sdpd-request.c src/bluetoothd-sdpd-request.obj: src/sdpd-request.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-request.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-request.Tpo -c -o src/bluetoothd-sdpd-request.obj `if test -f 'src/sdpd-request.c'; then $(CYGPATH_W) 'src/sdpd-request.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-request.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-request.Tpo src/$(DEPDIR)/bluetoothd-sdpd-request.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-request.c' object='src/bluetoothd-sdpd-request.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-request.obj `if test -f 'src/sdpd-request.c'; then $(CYGPATH_W) 'src/sdpd-request.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-request.c'; fi` src/bluetoothd-sdpd-service.o: src/sdpd-service.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-service.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-service.Tpo -c -o src/bluetoothd-sdpd-service.o `test -f 'src/sdpd-service.c' || echo '$(srcdir)/'`src/sdpd-service.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-service.Tpo src/$(DEPDIR)/bluetoothd-sdpd-service.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-service.c' object='src/bluetoothd-sdpd-service.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-service.o `test -f 'src/sdpd-service.c' || echo '$(srcdir)/'`src/sdpd-service.c src/bluetoothd-sdpd-service.obj: src/sdpd-service.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-service.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-service.Tpo -c -o src/bluetoothd-sdpd-service.obj `if test -f 'src/sdpd-service.c'; then $(CYGPATH_W) 'src/sdpd-service.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-service.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-service.Tpo src/$(DEPDIR)/bluetoothd-sdpd-service.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-service.c' object='src/bluetoothd-sdpd-service.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-service.obj `if test -f 'src/sdpd-service.c'; then $(CYGPATH_W) 'src/sdpd-service.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-service.c'; fi` src/bluetoothd-sdpd-database.o: src/sdpd-database.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-database.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-database.Tpo -c -o src/bluetoothd-sdpd-database.o `test -f 'src/sdpd-database.c' || echo '$(srcdir)/'`src/sdpd-database.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-database.Tpo src/$(DEPDIR)/bluetoothd-sdpd-database.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-database.c' object='src/bluetoothd-sdpd-database.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-database.o `test -f 'src/sdpd-database.c' || echo '$(srcdir)/'`src/sdpd-database.c src/bluetoothd-sdpd-database.obj: src/sdpd-database.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdpd-database.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdpd-database.Tpo -c -o src/bluetoothd-sdpd-database.obj `if test -f 'src/sdpd-database.c'; then $(CYGPATH_W) 'src/sdpd-database.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-database.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdpd-database.Tpo src/$(DEPDIR)/bluetoothd-sdpd-database.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdpd-database.c' object='src/bluetoothd-sdpd-database.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdpd-database.obj `if test -f 'src/sdpd-database.c'; then $(CYGPATH_W) 'src/sdpd-database.c'; else $(CYGPATH_W) '$(srcdir)/src/sdpd-database.c'; fi` src/bluetoothd-attrib-server.o: src/attrib-server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-attrib-server.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-attrib-server.Tpo -c -o src/bluetoothd-attrib-server.o `test -f 'src/attrib-server.c' || echo '$(srcdir)/'`src/attrib-server.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-attrib-server.Tpo src/$(DEPDIR)/bluetoothd-attrib-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/attrib-server.c' object='src/bluetoothd-attrib-server.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-attrib-server.o `test -f 'src/attrib-server.c' || echo '$(srcdir)/'`src/attrib-server.c src/bluetoothd-attrib-server.obj: src/attrib-server.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-attrib-server.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-attrib-server.Tpo -c -o src/bluetoothd-attrib-server.obj `if test -f 'src/attrib-server.c'; then $(CYGPATH_W) 'src/attrib-server.c'; else $(CYGPATH_W) '$(srcdir)/src/attrib-server.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-attrib-server.Tpo src/$(DEPDIR)/bluetoothd-attrib-server.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/attrib-server.c' object='src/bluetoothd-attrib-server.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-attrib-server.obj `if test -f 'src/attrib-server.c'; then $(CYGPATH_W) 'src/attrib-server.c'; else $(CYGPATH_W) '$(srcdir)/src/attrib-server.c'; fi` src/bluetoothd-sdp-xml.o: src/sdp-xml.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdp-xml.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdp-xml.Tpo -c -o src/bluetoothd-sdp-xml.o `test -f 'src/sdp-xml.c' || echo '$(srcdir)/'`src/sdp-xml.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdp-xml.Tpo src/$(DEPDIR)/bluetoothd-sdp-xml.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdp-xml.c' object='src/bluetoothd-sdp-xml.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdp-xml.o `test -f 'src/sdp-xml.c' || echo '$(srcdir)/'`src/sdp-xml.c src/bluetoothd-sdp-xml.obj: src/sdp-xml.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdp-xml.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdp-xml.Tpo -c -o src/bluetoothd-sdp-xml.obj `if test -f 'src/sdp-xml.c'; then $(CYGPATH_W) 'src/sdp-xml.c'; else $(CYGPATH_W) '$(srcdir)/src/sdp-xml.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdp-xml.Tpo src/$(DEPDIR)/bluetoothd-sdp-xml.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdp-xml.c' object='src/bluetoothd-sdp-xml.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdp-xml.obj `if test -f 'src/sdp-xml.c'; then $(CYGPATH_W) 'src/sdp-xml.c'; else $(CYGPATH_W) '$(srcdir)/src/sdp-xml.c'; fi` src/bluetoothd-sdp-client.o: src/sdp-client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdp-client.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdp-client.Tpo -c -o src/bluetoothd-sdp-client.o `test -f 'src/sdp-client.c' || echo '$(srcdir)/'`src/sdp-client.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdp-client.Tpo src/$(DEPDIR)/bluetoothd-sdp-client.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdp-client.c' object='src/bluetoothd-sdp-client.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdp-client.o `test -f 'src/sdp-client.c' || echo '$(srcdir)/'`src/sdp-client.c src/bluetoothd-sdp-client.obj: src/sdp-client.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-sdp-client.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-sdp-client.Tpo -c -o src/bluetoothd-sdp-client.obj `if test -f 'src/sdp-client.c'; then $(CYGPATH_W) 'src/sdp-client.c'; else $(CYGPATH_W) '$(srcdir)/src/sdp-client.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-sdp-client.Tpo src/$(DEPDIR)/bluetoothd-sdp-client.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/sdp-client.c' object='src/bluetoothd-sdp-client.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-sdp-client.obj `if test -f 'src/sdp-client.c'; then $(CYGPATH_W) 'src/sdp-client.c'; else $(CYGPATH_W) '$(srcdir)/src/sdp-client.c'; fi` src/bluetoothd-textfile.o: src/textfile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-textfile.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-textfile.Tpo -c -o src/bluetoothd-textfile.o `test -f 'src/textfile.c' || echo '$(srcdir)/'`src/textfile.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-textfile.Tpo src/$(DEPDIR)/bluetoothd-textfile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/textfile.c' object='src/bluetoothd-textfile.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-textfile.o `test -f 'src/textfile.c' || echo '$(srcdir)/'`src/textfile.c src/bluetoothd-textfile.obj: src/textfile.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-textfile.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-textfile.Tpo -c -o src/bluetoothd-textfile.obj `if test -f 'src/textfile.c'; then $(CYGPATH_W) 'src/textfile.c'; else $(CYGPATH_W) '$(srcdir)/src/textfile.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-textfile.Tpo src/$(DEPDIR)/bluetoothd-textfile.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/textfile.c' object='src/bluetoothd-textfile.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-textfile.obj `if test -f 'src/textfile.c'; then $(CYGPATH_W) 'src/textfile.c'; else $(CYGPATH_W) '$(srcdir)/src/textfile.c'; fi` src/bluetoothd-glib-helper.o: src/glib-helper.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-glib-helper.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-glib-helper.Tpo -c -o src/bluetoothd-glib-helper.o `test -f 'src/glib-helper.c' || echo '$(srcdir)/'`src/glib-helper.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-glib-helper.Tpo src/$(DEPDIR)/bluetoothd-glib-helper.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/glib-helper.c' object='src/bluetoothd-glib-helper.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-glib-helper.o `test -f 'src/glib-helper.c' || echo '$(srcdir)/'`src/glib-helper.c src/bluetoothd-glib-helper.obj: src/glib-helper.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-glib-helper.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-glib-helper.Tpo -c -o src/bluetoothd-glib-helper.obj `if test -f 'src/glib-helper.c'; then $(CYGPATH_W) 'src/glib-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/glib-helper.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-glib-helper.Tpo src/$(DEPDIR)/bluetoothd-glib-helper.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/glib-helper.c' object='src/bluetoothd-glib-helper.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-glib-helper.obj `if test -f 'src/glib-helper.c'; then $(CYGPATH_W) 'src/glib-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/glib-helper.c'; fi` src/bluetoothd-oui.o: src/oui.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-oui.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-oui.Tpo -c -o src/bluetoothd-oui.o `test -f 'src/oui.c' || echo '$(srcdir)/'`src/oui.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-oui.Tpo src/$(DEPDIR)/bluetoothd-oui.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/oui.c' object='src/bluetoothd-oui.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-oui.o `test -f 'src/oui.c' || echo '$(srcdir)/'`src/oui.c src/bluetoothd-oui.obj: src/oui.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-oui.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-oui.Tpo -c -o src/bluetoothd-oui.obj `if test -f 'src/oui.c'; then $(CYGPATH_W) 'src/oui.c'; else $(CYGPATH_W) '$(srcdir)/src/oui.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-oui.Tpo src/$(DEPDIR)/bluetoothd-oui.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/oui.c' object='src/bluetoothd-oui.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-oui.obj `if test -f 'src/oui.c'; then $(CYGPATH_W) 'src/oui.c'; else $(CYGPATH_W) '$(srcdir)/src/oui.c'; fi` src/bluetoothd-plugin.o: src/plugin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-plugin.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-plugin.Tpo -c -o src/bluetoothd-plugin.o `test -f 'src/plugin.c' || echo '$(srcdir)/'`src/plugin.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-plugin.Tpo src/$(DEPDIR)/bluetoothd-plugin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/plugin.c' object='src/bluetoothd-plugin.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-plugin.o `test -f 'src/plugin.c' || echo '$(srcdir)/'`src/plugin.c src/bluetoothd-plugin.obj: src/plugin.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-plugin.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-plugin.Tpo -c -o src/bluetoothd-plugin.obj `if test -f 'src/plugin.c'; then $(CYGPATH_W) 'src/plugin.c'; else $(CYGPATH_W) '$(srcdir)/src/plugin.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-plugin.Tpo src/$(DEPDIR)/bluetoothd-plugin.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/plugin.c' object='src/bluetoothd-plugin.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-plugin.obj `if test -f 'src/plugin.c'; then $(CYGPATH_W) 'src/plugin.c'; else $(CYGPATH_W) '$(srcdir)/src/plugin.c'; fi` src/bluetoothd-storage.o: src/storage.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-storage.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-storage.Tpo -c -o src/bluetoothd-storage.o `test -f 'src/storage.c' || echo '$(srcdir)/'`src/storage.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-storage.Tpo src/$(DEPDIR)/bluetoothd-storage.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/storage.c' object='src/bluetoothd-storage.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-storage.o `test -f 'src/storage.c' || echo '$(srcdir)/'`src/storage.c src/bluetoothd-storage.obj: src/storage.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-storage.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-storage.Tpo -c -o src/bluetoothd-storage.obj `if test -f 'src/storage.c'; then $(CYGPATH_W) 'src/storage.c'; else $(CYGPATH_W) '$(srcdir)/src/storage.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-storage.Tpo src/$(DEPDIR)/bluetoothd-storage.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/storage.c' object='src/bluetoothd-storage.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-storage.obj `if test -f 'src/storage.c'; then $(CYGPATH_W) 'src/storage.c'; else $(CYGPATH_W) '$(srcdir)/src/storage.c'; fi` src/bluetoothd-agent.o: src/agent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-agent.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-agent.Tpo -c -o src/bluetoothd-agent.o `test -f 'src/agent.c' || echo '$(srcdir)/'`src/agent.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-agent.Tpo src/$(DEPDIR)/bluetoothd-agent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/agent.c' object='src/bluetoothd-agent.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-agent.o `test -f 'src/agent.c' || echo '$(srcdir)/'`src/agent.c src/bluetoothd-agent.obj: src/agent.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-agent.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-agent.Tpo -c -o src/bluetoothd-agent.obj `if test -f 'src/agent.c'; then $(CYGPATH_W) 'src/agent.c'; else $(CYGPATH_W) '$(srcdir)/src/agent.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-agent.Tpo src/$(DEPDIR)/bluetoothd-agent.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/agent.c' object='src/bluetoothd-agent.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-agent.obj `if test -f 'src/agent.c'; then $(CYGPATH_W) 'src/agent.c'; else $(CYGPATH_W) '$(srcdir)/src/agent.c'; fi` src/bluetoothd-error.o: src/error.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-error.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-error.Tpo -c -o src/bluetoothd-error.o `test -f 'src/error.c' || echo '$(srcdir)/'`src/error.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-error.Tpo src/$(DEPDIR)/bluetoothd-error.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/error.c' object='src/bluetoothd-error.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-error.o `test -f 'src/error.c' || echo '$(srcdir)/'`src/error.c src/bluetoothd-error.obj: src/error.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-error.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-error.Tpo -c -o src/bluetoothd-error.obj `if test -f 'src/error.c'; then $(CYGPATH_W) 'src/error.c'; else $(CYGPATH_W) '$(srcdir)/src/error.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-error.Tpo src/$(DEPDIR)/bluetoothd-error.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/error.c' object='src/bluetoothd-error.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-error.obj `if test -f 'src/error.c'; then $(CYGPATH_W) 'src/error.c'; else $(CYGPATH_W) '$(srcdir)/src/error.c'; fi` src/bluetoothd-manager.o: src/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-manager.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-manager.Tpo -c -o src/bluetoothd-manager.o `test -f 'src/manager.c' || echo '$(srcdir)/'`src/manager.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-manager.Tpo src/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/manager.c' object='src/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-manager.o `test -f 'src/manager.c' || echo '$(srcdir)/'`src/manager.c src/bluetoothd-manager.obj: src/manager.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-manager.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-manager.Tpo -c -o src/bluetoothd-manager.obj `if test -f 'src/manager.c'; then $(CYGPATH_W) 'src/manager.c'; else $(CYGPATH_W) '$(srcdir)/src/manager.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-manager.Tpo src/$(DEPDIR)/bluetoothd-manager.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/manager.c' object='src/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-manager.obj `if test -f 'src/manager.c'; then $(CYGPATH_W) 'src/manager.c'; else $(CYGPATH_W) '$(srcdir)/src/manager.c'; fi` src/bluetoothd-adapter.o: src/adapter.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-adapter.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-adapter.Tpo -c -o src/bluetoothd-adapter.o `test -f 'src/adapter.c' || echo '$(srcdir)/'`src/adapter.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-adapter.Tpo src/$(DEPDIR)/bluetoothd-adapter.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/adapter.c' object='src/bluetoothd-adapter.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-adapter.o `test -f 'src/adapter.c' || echo '$(srcdir)/'`src/adapter.c src/bluetoothd-adapter.obj: src/adapter.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-adapter.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-adapter.Tpo -c -o src/bluetoothd-adapter.obj `if test -f 'src/adapter.c'; then $(CYGPATH_W) 'src/adapter.c'; else $(CYGPATH_W) '$(srcdir)/src/adapter.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-adapter.Tpo src/$(DEPDIR)/bluetoothd-adapter.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/adapter.c' object='src/bluetoothd-adapter.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-adapter.obj `if test -f 'src/adapter.c'; then $(CYGPATH_W) 'src/adapter.c'; else $(CYGPATH_W) '$(srcdir)/src/adapter.c'; fi` src/bluetoothd-device.o: src/device.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-device.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-device.Tpo -c -o src/bluetoothd-device.o `test -f 'src/device.c' || echo '$(srcdir)/'`src/device.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-device.Tpo src/$(DEPDIR)/bluetoothd-device.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/device.c' object='src/bluetoothd-device.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-device.o `test -f 'src/device.c' || echo '$(srcdir)/'`src/device.c src/bluetoothd-device.obj: src/device.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-device.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-device.Tpo -c -o src/bluetoothd-device.obj `if test -f 'src/device.c'; then $(CYGPATH_W) 'src/device.c'; else $(CYGPATH_W) '$(srcdir)/src/device.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-device.Tpo src/$(DEPDIR)/bluetoothd-device.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/device.c' object='src/bluetoothd-device.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-device.obj `if test -f 'src/device.c'; then $(CYGPATH_W) 'src/device.c'; else $(CYGPATH_W) '$(srcdir)/src/device.c'; fi` src/bluetoothd-dbus-common.o: src/dbus-common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-dbus-common.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-dbus-common.Tpo -c -o src/bluetoothd-dbus-common.o `test -f 'src/dbus-common.c' || echo '$(srcdir)/'`src/dbus-common.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-dbus-common.Tpo src/$(DEPDIR)/bluetoothd-dbus-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/dbus-common.c' object='src/bluetoothd-dbus-common.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-dbus-common.o `test -f 'src/dbus-common.c' || echo '$(srcdir)/'`src/dbus-common.c src/bluetoothd-dbus-common.obj: src/dbus-common.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-dbus-common.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-dbus-common.Tpo -c -o src/bluetoothd-dbus-common.obj `if test -f 'src/dbus-common.c'; then $(CYGPATH_W) 'src/dbus-common.c'; else $(CYGPATH_W) '$(srcdir)/src/dbus-common.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-dbus-common.Tpo src/$(DEPDIR)/bluetoothd-dbus-common.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/dbus-common.c' object='src/bluetoothd-dbus-common.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-dbus-common.obj `if test -f 'src/dbus-common.c'; then $(CYGPATH_W) 'src/dbus-common.c'; else $(CYGPATH_W) '$(srcdir)/src/dbus-common.c'; fi` src/bluetoothd-event.o: src/event.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-event.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-event.Tpo -c -o src/bluetoothd-event.o `test -f 'src/event.c' || echo '$(srcdir)/'`src/event.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-event.Tpo src/$(DEPDIR)/bluetoothd-event.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/event.c' object='src/bluetoothd-event.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-event.o `test -f 'src/event.c' || echo '$(srcdir)/'`src/event.c src/bluetoothd-event.obj: src/event.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-event.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-event.Tpo -c -o src/bluetoothd-event.obj `if test -f 'src/event.c'; then $(CYGPATH_W) 'src/event.c'; else $(CYGPATH_W) '$(srcdir)/src/event.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-event.Tpo src/$(DEPDIR)/bluetoothd-event.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/event.c' object='src/bluetoothd-event.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-event.obj `if test -f 'src/event.c'; then $(CYGPATH_W) 'src/event.c'; else $(CYGPATH_W) '$(srcdir)/src/event.c'; fi` src/bluetoothd-oob.o: src/oob.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-oob.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-oob.Tpo -c -o src/bluetoothd-oob.o `test -f 'src/oob.c' || echo '$(srcdir)/'`src/oob.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-oob.Tpo src/$(DEPDIR)/bluetoothd-oob.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/oob.c' object='src/bluetoothd-oob.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-oob.o `test -f 'src/oob.c' || echo '$(srcdir)/'`src/oob.c src/bluetoothd-oob.obj: src/oob.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-oob.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-oob.Tpo -c -o src/bluetoothd-oob.obj `if test -f 'src/oob.c'; then $(CYGPATH_W) 'src/oob.c'; else $(CYGPATH_W) '$(srcdir)/src/oob.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-oob.Tpo src/$(DEPDIR)/bluetoothd-oob.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/oob.c' object='src/bluetoothd-oob.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-oob.obj `if test -f 'src/oob.c'; then $(CYGPATH_W) 'src/oob.c'; else $(CYGPATH_W) '$(srcdir)/src/oob.c'; fi` src/bluetoothd-eir.o: src/eir.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-eir.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-eir.Tpo -c -o src/bluetoothd-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-eir.Tpo src/$(DEPDIR)/bluetoothd-eir.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/eir.c' object='src/bluetoothd-eir.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c src/bluetoothd-eir.obj: src/eir.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-eir.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-eir.Tpo -c -o src/bluetoothd-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-eir.Tpo src/$(DEPDIR)/bluetoothd-eir.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/eir.c' object='src/bluetoothd-eir.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi` audio/bluetoothd-telephony.o: audio/telephony.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-telephony.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-telephony.Tpo -c -o audio/bluetoothd-telephony.o `test -f 'audio/telephony.c' || echo '$(srcdir)/'`audio/telephony.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-telephony.Tpo audio/$(DEPDIR)/bluetoothd-telephony.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/telephony.c' object='audio/bluetoothd-telephony.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-telephony.o `test -f 'audio/telephony.c' || echo '$(srcdir)/'`audio/telephony.c audio/bluetoothd-telephony.obj: audio/telephony.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-telephony.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-telephony.Tpo -c -o audio/bluetoothd-telephony.obj `if test -f 'audio/telephony.c'; then $(CYGPATH_W) 'audio/telephony.c'; else $(CYGPATH_W) '$(srcdir)/audio/telephony.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-telephony.Tpo audio/$(DEPDIR)/bluetoothd-telephony.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='audio/telephony.c' object='audio/bluetoothd-telephony.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-telephony.obj `if test -f 'audio/telephony.c'; then $(CYGPATH_W) 'audio/telephony.c'; else $(CYGPATH_W) '$(srcdir)/audio/telephony.c'; fi` sap/bluetoothd-sap.o: sap/sap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-sap.o -MD -MP -MF sap/$(DEPDIR)/bluetoothd-sap.Tpo -c -o sap/bluetoothd-sap.o `test -f 'sap/sap.c' || echo '$(srcdir)/'`sap/sap.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-sap.Tpo sap/$(DEPDIR)/bluetoothd-sap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sap/sap.c' object='sap/bluetoothd-sap.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-sap.o `test -f 'sap/sap.c' || echo '$(srcdir)/'`sap/sap.c sap/bluetoothd-sap.obj: sap/sap.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-sap.obj -MD -MP -MF sap/$(DEPDIR)/bluetoothd-sap.Tpo -c -o sap/bluetoothd-sap.obj `if test -f 'sap/sap.c'; then $(CYGPATH_W) 'sap/sap.c'; else $(CYGPATH_W) '$(srcdir)/sap/sap.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-sap.Tpo sap/$(DEPDIR)/bluetoothd-sap.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sap/sap.c' object='sap/bluetoothd-sap.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-sap.obj `if test -f 'sap/sap.c'; then $(CYGPATH_W) 'sap/sap.c'; else $(CYGPATH_W) '$(srcdir)/sap/sap.c'; fi` unit/unit_test_eir-test-eir.o: unit/test-eir.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT unit/unit_test_eir-test-eir.o -MD -MP -MF unit/$(DEPDIR)/unit_test_eir-test-eir.Tpo -c -o unit/unit_test_eir-test-eir.o `test -f 'unit/test-eir.c' || echo '$(srcdir)/'`unit/test-eir.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) unit/$(DEPDIR)/unit_test_eir-test-eir.Tpo unit/$(DEPDIR)/unit_test_eir-test-eir.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit/test-eir.c' object='unit/unit_test_eir-test-eir.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o unit/unit_test_eir-test-eir.o `test -f 'unit/test-eir.c' || echo '$(srcdir)/'`unit/test-eir.c unit/unit_test_eir-test-eir.obj: unit/test-eir.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT unit/unit_test_eir-test-eir.obj -MD -MP -MF unit/$(DEPDIR)/unit_test_eir-test-eir.Tpo -c -o unit/unit_test_eir-test-eir.obj `if test -f 'unit/test-eir.c'; then $(CYGPATH_W) 'unit/test-eir.c'; else $(CYGPATH_W) '$(srcdir)/unit/test-eir.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) unit/$(DEPDIR)/unit_test_eir-test-eir.Tpo unit/$(DEPDIR)/unit_test_eir-test-eir.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='unit/test-eir.c' object='unit/unit_test_eir-test-eir.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o unit/unit_test_eir-test-eir.obj `if test -f 'unit/test-eir.c'; then $(CYGPATH_W) 'unit/test-eir.c'; else $(CYGPATH_W) '$(srcdir)/unit/test-eir.c'; fi` src/unit_test_eir-eir.o: src/eir.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT src/unit_test_eir-eir.o -MD -MP -MF src/$(DEPDIR)/unit_test_eir-eir.Tpo -c -o src/unit_test_eir-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/unit_test_eir-eir.Tpo src/$(DEPDIR)/unit_test_eir-eir.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/eir.c' object='src/unit_test_eir-eir.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o src/unit_test_eir-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c src/unit_test_eir-eir.obj: src/eir.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT src/unit_test_eir-eir.obj -MD -MP -MF src/$(DEPDIR)/unit_test_eir-eir.Tpo -c -o src/unit_test_eir-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/unit_test_eir-eir.Tpo src/$(DEPDIR)/unit_test_eir-eir.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/eir.c' object='src/unit_test_eir-eir.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o src/unit_test_eir-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi` src/unit_test_eir-glib-helper.o: src/glib-helper.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT src/unit_test_eir-glib-helper.o -MD -MP -MF src/$(DEPDIR)/unit_test_eir-glib-helper.Tpo -c -o src/unit_test_eir-glib-helper.o `test -f 'src/glib-helper.c' || echo '$(srcdir)/'`src/glib-helper.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/unit_test_eir-glib-helper.Tpo src/$(DEPDIR)/unit_test_eir-glib-helper.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/glib-helper.c' object='src/unit_test_eir-glib-helper.o' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o src/unit_test_eir-glib-helper.o `test -f 'src/glib-helper.c' || echo '$(srcdir)/'`src/glib-helper.c src/unit_test_eir-glib-helper.obj: src/glib-helper.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT src/unit_test_eir-glib-helper.obj -MD -MP -MF src/$(DEPDIR)/unit_test_eir-glib-helper.Tpo -c -o src/unit_test_eir-glib-helper.obj `if test -f 'src/glib-helper.c'; then $(CYGPATH_W) 'src/glib-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/glib-helper.c'; fi` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) src/$(DEPDIR)/unit_test_eir-glib-helper.Tpo src/$(DEPDIR)/unit_test_eir-glib-helper.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='src/glib-helper.c' object='src/unit_test_eir-glib-helper.obj' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o src/unit_test_eir-glib-helper.obj `if test -f 'src/glib-helper.c'; then $(CYGPATH_W) 'src/glib-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/glib-helper.c'; fi` .l.c: $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE) .y.c: $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) mostlyclean-libtool: -rm -f *.lo clean-libtool: -rm -rf .libs _libs -rm -rf attrib/.libs attrib/_libs -rm -rf audio/.libs audio/_libs -rm -rf compat/.libs compat/_libs -rm -rf cups/.libs cups/_libs -rm -rf emulator/.libs emulator/_libs -rm -rf lib/.libs lib/_libs -rm -rf mgmt/.libs mgmt/_libs -rm -rf monitor/.libs monitor/_libs -rm -rf plugins/.libs plugins/_libs -rm -rf sbc/.libs sbc/_libs -rm -rf src/.libs src/_libs -rm -rf test/.libs test/_libs -rm -rf tools/.libs tools/_libs -rm -rf unit/.libs unit/_libs distclean-libtool: -rm -f libtool config.lt install-man1: $(dist_man_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)" @list=''; test -n "$(man1dir)" || exit 0; \ { for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS) $(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \ done; } uninstall-man1: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man1dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS) $(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.1[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir) install-man8: $(dist_man_MANS) $(man_MANS) @$(NORMAL_INSTALL) test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)" @list=''; test -n "$(man8dir)" || exit 0; \ { for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS) $(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.8[a-z]*$$/p'; \ } | while read p; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; echo "$$p"; \ done | \ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ sed 'N;N;s,\n, ,g' | { \ list=; while read file base inst; do \ if test "$$base" = "$$inst"; then list="$$list $$file"; else \ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man8dir)/$$inst'"; \ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man8dir)/$$inst" || exit $$?; \ fi; \ done; \ for i in $$list; do echo "$$i"; done | $(am__base_list) | \ while read files; do \ test -z "$$files" || { \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man8dir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(man8dir)" || exit $$?; }; \ done; } uninstall-man8: @$(NORMAL_UNINSTALL) @list=''; test -n "$(man8dir)" || exit 0; \ files=`{ for i in $$list; do echo "$$i"; done; \ l2='$(dist_man_MANS) $(man_MANS)'; for i in $$l2; do echo "$$i"; done | \ sed -n '/\.8[a-z]*$$/p'; \ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir) install-alsaconfDATA: $(alsaconf_DATA) @$(NORMAL_INSTALL) test -z "$(alsaconfdir)" || $(MKDIR_P) "$(DESTDIR)$(alsaconfdir)" @list='$(alsaconf_DATA)'; test -n "$(alsaconfdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(alsaconfdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(alsaconfdir)" || exit $$?; \ done uninstall-alsaconfDATA: @$(NORMAL_UNINSTALL) @list='$(alsaconf_DATA)'; test -n "$(alsaconfdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(alsaconfdir)'; $(am__uninstall_files_from_dir) install-confDATA: $(conf_DATA) @$(NORMAL_INSTALL) test -z "$(confdir)" || $(MKDIR_P) "$(DESTDIR)$(confdir)" @list='$(conf_DATA)'; test -n "$(confdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(confdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(confdir)" || exit $$?; \ done uninstall-confDATA: @$(NORMAL_UNINSTALL) @list='$(conf_DATA)'; test -n "$(confdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(confdir)'; $(am__uninstall_files_from_dir) install-dbusDATA: $(dbus_DATA) @$(NORMAL_INSTALL) test -z "$(dbusdir)" || $(MKDIR_P) "$(DESTDIR)$(dbusdir)" @list='$(dbus_DATA)'; test -n "$(dbusdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbusdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(dbusdir)" || exit $$?; \ done uninstall-dbusDATA: @$(NORMAL_UNINSTALL) @list='$(dbus_DATA)'; test -n "$(dbusdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(dbusdir)'; $(am__uninstall_files_from_dir) install-dbusserviceDATA: $(dbusservice_DATA) @$(NORMAL_INSTALL) test -z "$(dbusservicedir)" || $(MKDIR_P) "$(DESTDIR)$(dbusservicedir)" @list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbusservicedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(dbusservicedir)" || exit $$?; \ done uninstall-dbusserviceDATA: @$(NORMAL_UNINSTALL) @list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(dbusservicedir)'; $(am__uninstall_files_from_dir) install-pkgconfigDATA: $(pkgconfig_DATA) @$(NORMAL_INSTALL) test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ done uninstall-pkgconfigDATA: @$(NORMAL_UNINSTALL) @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) install-rulesDATA: $(rules_DATA) @$(NORMAL_INSTALL) test -z "$(rulesdir)" || $(MKDIR_P) "$(DESTDIR)$(rulesdir)" @list='$(rules_DATA)'; test -n "$(rulesdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(rulesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(rulesdir)" || exit $$?; \ done uninstall-rulesDATA: @$(NORMAL_UNINSTALL) @list='$(rules_DATA)'; test -n "$(rulesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(rulesdir)'; $(am__uninstall_files_from_dir) install-stateDATA: $(state_DATA) @$(NORMAL_INSTALL) test -z "$(statedir)" || $(MKDIR_P) "$(DESTDIR)$(statedir)" @list='$(state_DATA)'; test -n "$(statedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(statedir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(statedir)" || exit $$?; \ done uninstall-stateDATA: @$(NORMAL_UNINSTALL) @list='$(state_DATA)'; test -n "$(statedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(statedir)'; $(am__uninstall_files_from_dir) install-systemdunitDATA: $(systemdunit_DATA) @$(NORMAL_INSTALL) test -z "$(systemdunitdir)" || $(MKDIR_P) "$(DESTDIR)$(systemdunitdir)" @list='$(systemdunit_DATA)'; test -n "$(systemdunitdir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdunitdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdunitdir)" || exit $$?; \ done uninstall-systemdunitDATA: @$(NORMAL_UNINSTALL) @list='$(systemdunit_DATA)'; test -n "$(systemdunitdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(systemdunitdir)'; $(am__uninstall_files_from_dir) install-includeHEADERS: $(include_HEADERS) @$(NORMAL_INSTALL) test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)" @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ done uninstall-includeHEADERS: @$(NORMAL_UNINSTALL) @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ mkid -fID $$unique tags: TAGS TAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) set x; \ here=`pwd`; \ list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: CTAGS CTAGS: $(HEADERS) $(SOURCES) config.h.in $(TAGS_DEPENDENCIES) \ $(TAGS_FILES) $(LISP) list='$(SOURCES) $(HEADERS) config.h.in $(LISP) $(TAGS_FILES)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | \ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in files) print i; }; }'`; \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags check-TESTS: $(TESTS) @failed=0; all=0; xfail=0; xpass=0; skip=0; \ srcdir=$(srcdir); export srcdir; \ list=' $(TESTS) '; \ $(am__tty_colors); \ if test -n "$$list"; then \ for tst in $$list; do \ if test -f ./$$tst; then dir=./; \ elif test -f $$tst; then dir=; \ else dir="$(srcdir)/"; fi; \ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xpass=`expr $$xpass + 1`; \ failed=`expr $$failed + 1`; \ col=$$red; res=XPASS; \ ;; \ *) \ col=$$grn; res=PASS; \ ;; \ esac; \ elif test $$? -ne 77; then \ all=`expr $$all + 1`; \ case " $(XFAIL_TESTS) " in \ *[\ \ ]$$tst[\ \ ]*) \ xfail=`expr $$xfail + 1`; \ col=$$lgn; res=XFAIL; \ ;; \ *) \ failed=`expr $$failed + 1`; \ col=$$red; res=FAIL; \ ;; \ esac; \ else \ skip=`expr $$skip + 1`; \ col=$$blu; res=SKIP; \ fi; \ echo "$${col}$$res$${std}: $$tst"; \ done; \ if test "$$all" -eq 1; then \ tests="test"; \ All=""; \ else \ tests="tests"; \ All="All "; \ fi; \ if test "$$failed" -eq 0; then \ if test "$$xfail" -eq 0; then \ banner="$$All$$all $$tests passed"; \ else \ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \ fi; \ else \ if test "$$xpass" -eq 0; then \ banner="$$failed of $$all $$tests failed"; \ else \ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \ fi; \ fi; \ dashes="$$banner"; \ skipped=""; \ if test "$$skip" -ne 0; then \ if test "$$skip" -eq 1; then \ skipped="($$skip test was not run)"; \ else \ skipped="($$skip tests were not run)"; \ fi; \ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$skipped"; \ fi; \ report=""; \ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \ report="Please report to $(PACKAGE_BUGREPORT)"; \ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \ dashes="$$report"; \ fi; \ dashes=`echo "$$dashes" | sed s/./=/g`; \ if test "$$failed" -eq 0; then \ col="$$grn"; \ else \ col="$$red"; \ fi; \ echo "$${col}$$dashes$${std}"; \ echo "$${col}$$banner$${std}"; \ test -z "$$skipped" || echo "$${col}$$skipped$${std}"; \ test -z "$$report" || echo "$${col}$$report$${std}"; \ echo "$${col}$$dashes$${std}"; \ test "$$failed" -eq 0; \ else :; fi distdir: $(DISTFILES) @list='$(MANS)'; if test -n "$$list"; then \ list=`for p in $$list; do \ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ if test -f "$$d$$p"; then echo "$$d$$p"; else :; fi; done`; \ if test -n "$$list" && \ grep 'ab help2man is required to generate this page' $$list >/dev/null; then \ echo "error: found man pages containing the \`missing help2man' replacement text:" >&2; \ grep -l 'ab help2man is required to generate this page' $$list | sed 's/^/ /' >&2; \ echo " to fix them, install help2man, remove and regenerate the man pages;" >&2; \ echo " typically \`make maintainer-clean' will remove them" >&2; \ exit 1; \ else :; fi; \ else :; fi $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__remove_distdir) dist-lzma: distdir tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma $(am__remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__remove_distdir) dist-tarZ: distdir tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__remove_distdir) dist-shar: distdir shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__remove_distdir) dist dist-all: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lzma*) \ lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir); chmod a+w $(distdir) mkdir $(distdir)/_build mkdir $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure --srcdir=.. --prefix="$$dc_install_base" \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am $(MAKE) $(AM_MAKEFLAGS) check-TESTS check: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) check-am all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) \ $(MANS) $(DATA) $(HEADERS) config.h install-binPROGRAMS: install-libLTLIBRARIES installdirs: for dir in "$(DESTDIR)$(alsadir)" "$(DESTDIR)$(gstreamerdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cupsdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(alsaconfdir)" "$(DESTDIR)$(confdir)" "$(DESTDIR)$(dbusdir)" "$(DESTDIR)$(dbusservicedir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(rulesdir)" "$(DESTDIR)$(statedir)" "$(DESTDIR)$(systemdunitdir)" "$(DESTDIR)$(includedir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) -rm -f alert/$(DEPDIR)/$(am__dirstamp) -rm -f alert/$(am__dirstamp) -rm -f attrib/$(DEPDIR)/$(am__dirstamp) -rm -f attrib/$(am__dirstamp) -rm -f audio/$(DEPDIR)/$(am__dirstamp) -rm -f audio/$(am__dirstamp) -rm -f btio/$(DEPDIR)/$(am__dirstamp) -rm -f btio/$(am__dirstamp) -rm -f compat/$(DEPDIR)/$(am__dirstamp) -rm -f compat/$(am__dirstamp) -rm -f cups/$(DEPDIR)/$(am__dirstamp) -rm -f cups/$(am__dirstamp) -rm -f deviceinfo/$(DEPDIR)/$(am__dirstamp) -rm -f deviceinfo/$(am__dirstamp) -rm -f emulator/$(DEPDIR)/$(am__dirstamp) -rm -f emulator/$(am__dirstamp) -rm -f gdbus/$(DEPDIR)/$(am__dirstamp) -rm -f gdbus/$(am__dirstamp) -rm -f health/$(DEPDIR)/$(am__dirstamp) -rm -f health/$(am__dirstamp) -rm -f input/$(DEPDIR)/$(am__dirstamp) -rm -f input/$(am__dirstamp) -rm -f lib/$(DEPDIR)/$(am__dirstamp) -rm -f lib/$(am__dirstamp) -rm -f mgmt/$(DEPDIR)/$(am__dirstamp) -rm -f mgmt/$(am__dirstamp) -rm -f monitor/$(DEPDIR)/$(am__dirstamp) -rm -f monitor/$(am__dirstamp) -rm -f network/$(DEPDIR)/$(am__dirstamp) -rm -f network/$(am__dirstamp) -rm -f plugins/$(DEPDIR)/$(am__dirstamp) -rm -f plugins/$(am__dirstamp) -rm -f proximity/$(DEPDIR)/$(am__dirstamp) -rm -f proximity/$(am__dirstamp) -rm -f sap/$(DEPDIR)/$(am__dirstamp) -rm -f sap/$(am__dirstamp) -rm -f sbc/$(DEPDIR)/$(am__dirstamp) -rm -f sbc/$(am__dirstamp) -rm -f serial/$(DEPDIR)/$(am__dirstamp) -rm -f serial/$(am__dirstamp) -rm -f src/$(DEPDIR)/$(am__dirstamp) -rm -f src/$(am__dirstamp) -rm -f test/$(DEPDIR)/$(am__dirstamp) -rm -f test/$(am__dirstamp) -rm -f thermometer/$(DEPDIR)/$(am__dirstamp) -rm -f thermometer/$(am__dirstamp) -rm -f time/$(DEPDIR)/$(am__dirstamp) -rm -f time/$(am__dirstamp) -rm -f tools/$(DEPDIR)/$(am__dirstamp) -rm -f tools/$(am__dirstamp) -rm -f unit/$(DEPDIR)/$(am__dirstamp) -rm -f unit/$(am__dirstamp) -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." -rm -f tools/lexer.c -rm -f tools/parser.c -rm -f tools/parser.h -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) clean: clean-am clean-am: clean-alsaLTLIBRARIES clean-binPROGRAMS clean-cupsPROGRAMS \ clean-generic clean-gstreamerLTLIBRARIES clean-libLTLIBRARIES \ clean-libtool clean-local clean-noinstLIBRARIES \ clean-noinstLTLIBRARIES clean-noinstPROGRAMS \ clean-pluginLTLIBRARIES clean-sbinPROGRAMS clean-udevPROGRAMS \ mostlyclean-am distclean: distclean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf alert/$(DEPDIR) attrib/$(DEPDIR) audio/$(DEPDIR) btio/$(DEPDIR) compat/$(DEPDIR) cups/$(DEPDIR) deviceinfo/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) health/$(DEPDIR) input/$(DEPDIR) lib/$(DEPDIR) mgmt/$(DEPDIR) monitor/$(DEPDIR) network/$(DEPDIR) plugins/$(DEPDIR) proximity/$(DEPDIR) sap/$(DEPDIR) sbc/$(DEPDIR) serial/$(DEPDIR) src/$(DEPDIR) test/$(DEPDIR) thermometer/$(DEPDIR) time/$(DEPDIR) tools/$(DEPDIR) unit/$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-libtool distclean-tags dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-alsaLTLIBRARIES install-alsaconfDATA \ install-confDATA install-cupsPROGRAMS install-dbusDATA \ install-dbusserviceDATA install-dist_udevSCRIPTS \ install-gstreamerLTLIBRARIES install-includeHEADERS \ install-man install-pkgconfigDATA install-pluginLTLIBRARIES \ install-rulesDATA install-stateDATA install-systemdunitDATA \ install-udevPROGRAMS install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \ install-sbinPROGRAMS install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-man1 install-man8 install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf alert/$(DEPDIR) attrib/$(DEPDIR) audio/$(DEPDIR) btio/$(DEPDIR) compat/$(DEPDIR) cups/$(DEPDIR) deviceinfo/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) health/$(DEPDIR) input/$(DEPDIR) lib/$(DEPDIR) mgmt/$(DEPDIR) monitor/$(DEPDIR) network/$(DEPDIR) plugins/$(DEPDIR) proximity/$(DEPDIR) sap/$(DEPDIR) sbc/$(DEPDIR) serial/$(DEPDIR) src/$(DEPDIR) test/$(DEPDIR) thermometer/$(DEPDIR) time/$(DEPDIR) tools/$(DEPDIR) unit/$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-libtool pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: uninstall-alsaLTLIBRARIES uninstall-alsaconfDATA \ uninstall-binPROGRAMS uninstall-confDATA \ uninstall-cupsPROGRAMS uninstall-dbusDATA \ uninstall-dbusserviceDATA uninstall-dist_udevSCRIPTS \ uninstall-gstreamerLTLIBRARIES uninstall-includeHEADERS \ uninstall-libLTLIBRARIES uninstall-man uninstall-pkgconfigDATA \ uninstall-pluginLTLIBRARIES uninstall-rulesDATA \ uninstall-sbinPROGRAMS uninstall-stateDATA \ uninstall-systemdunitDATA uninstall-udevPROGRAMS uninstall-man: uninstall-man1 uninstall-man8 .MAKE: all check check-am install install-am install-strip .PHONY: CTAGS GTAGS all all-am am--refresh check check-TESTS check-am \ clean clean-alsaLTLIBRARIES clean-binPROGRAMS \ clean-cupsPROGRAMS clean-generic clean-gstreamerLTLIBRARIES \ clean-libLTLIBRARIES clean-libtool clean-local \ clean-noinstLIBRARIES clean-noinstLTLIBRARIES \ clean-noinstPROGRAMS clean-pluginLTLIBRARIES \ clean-sbinPROGRAMS clean-udevPROGRAMS ctags dist dist-all \ dist-bzip2 dist-gzip dist-lzip dist-lzma dist-shar dist-tarZ \ dist-xz dist-zip distcheck distclean distclean-compile \ distclean-generic distclean-hdr distclean-libtool \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install \ install-alsaLTLIBRARIES install-alsaconfDATA install-am \ install-binPROGRAMS install-confDATA install-cupsPROGRAMS \ install-data install-data-am install-dbusDATA \ install-dbusserviceDATA install-dist_udevSCRIPTS install-dvi \ install-dvi-am install-exec install-exec-am \ install-gstreamerLTLIBRARIES install-html install-html-am \ install-includeHEADERS install-info install-info-am \ install-libLTLIBRARIES install-man install-man1 install-man8 \ install-pdf install-pdf-am install-pkgconfigDATA \ install-pluginLTLIBRARIES install-ps install-ps-am \ install-rulesDATA install-sbinPROGRAMS install-stateDATA \ install-strip install-systemdunitDATA install-udevPROGRAMS \ installcheck installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-compile \ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ tags uninstall uninstall-alsaLTLIBRARIES \ uninstall-alsaconfDATA uninstall-am uninstall-binPROGRAMS \ uninstall-confDATA uninstall-cupsPROGRAMS uninstall-dbusDATA \ uninstall-dbusserviceDATA uninstall-dist_udevSCRIPTS \ uninstall-gstreamerLTLIBRARIES uninstall-includeHEADERS \ uninstall-libLTLIBRARIES uninstall-man uninstall-man1 \ uninstall-man8 uninstall-pkgconfigDATA \ uninstall-pluginLTLIBRARIES uninstall-rulesDATA \ uninstall-sbinPROGRAMS uninstall-stateDATA \ uninstall-systemdunitDATA uninstall-udevPROGRAMS @TOOLS_TRUE@tools/kword.c: tools/parser.h src/builtin.h: src/genbuiltin $(builtin_sources) $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@ audio/telephony.c: audio/@TELEPHONY_DRIVER@ $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@ sap/sap.c: sap/@SAP_DRIVER@ $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@ scripts/%.rules: $(AM_V_GEN)cp $(subst 97-,,$@) $@ $(lib_libbluetooth_la_OBJECTS): $(local_headers) lib/bluetooth/%.h: lib/%.h $(AM_V_at)$(MKDIR_P) lib/bluetooth $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@ clean-local: $(RM) -r lib/bluetooth # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: bluez-4.101/compat/0000755000000000000000000000000011771120005011064 500000000000000bluez-4.101/compat/sdp.h0000644000000000000000000000310011376221745011753 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define LANACCESS 0 #define MROUTER 1 #define ACTIVESYNC 2 #define DIALUP 3 int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req); int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req); int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len); int bnep_sdp_search(bdaddr_t *src, bdaddr_t *dst, uint16_t service); int bnep_sdp_register(bdaddr_t *device, uint16_t role); void bnep_sdp_unregister(void); int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel, int type); int dun_sdp_register(bdaddr_t *device, uint8_t channel, int type); void dun_sdp_unregister(void); bluez-4.101/compat/dund.c0000644000000000000000000003110611376221745012121 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "sdp.h" #include "dund.h" #include "lib.h" volatile sig_atomic_t __io_canceled; /* MS dialup networking support (i.e. CLIENT / CLIENTSERVER thing) */ static int msdun = 0; static char *pppd = "/usr/sbin/pppd"; static char *pppd_opts[DUN_MAX_PPP_OPTS] = { /* First 3 are reserved */ "", "", "", "noauth", "noipdefault", NULL }; static int detach = 1; static int persist; static int use_sdp = 1; static int auth; static int encrypt; static int secure; static int master; static int type = LANACCESS; static int search_duration = 10; static uint use_cache; static int channel; static struct { uint valid; char dst[40]; bdaddr_t bdaddr; int channel; } cache; static bdaddr_t src_addr = *BDADDR_ANY; static int src_dev = -1; volatile int terminate; enum { NONE, SHOW, LISTEN, CONNECT, KILL } modes; static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter); static int do_listen(void) { struct sockaddr_rc sa; int sk, lm; if (type == MROUTER) { if (!cache.valid) return -1; if (create_connection(cache.dst, &cache.bdaddr, type) < 0) { syslog(LOG_ERR, "Cannot connect to mRouter device. %s(%d)", strerror(errno), errno); return -1; } } if (!channel) channel = DUN_DEFAULT_CHANNEL; if (use_sdp) dun_sdp_register(&src_addr, channel, type); if (type == MROUTER) syslog(LOG_INFO, "Waiting for mRouter callback on channel %d", channel); /* Create RFCOMM socket */ sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sk < 0) { syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)", strerror(errno), errno); return -1; } sa.rc_family = AF_BLUETOOTH; sa.rc_channel = channel; sa.rc_bdaddr = src_addr; if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) { syslog(LOG_ERR, "Bind failed. %s(%d)", strerror(errno), errno); return -1; } /* Set link mode */ lm = 0; if (master) lm |= RFCOMM_LM_MASTER; if (auth) lm |= RFCOMM_LM_AUTH; if (encrypt) lm |= RFCOMM_LM_ENCRYPT; if (secure) lm |= RFCOMM_LM_SECURE; if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) { syslog(LOG_ERR, "Failed to set link mode. %s(%d)", strerror(errno), errno); return -1; } listen(sk, 10); while (!terminate) { socklen_t alen = sizeof(sa); int nsk; char ba[40]; char ch[10]; nsk = accept(sk, (struct sockaddr *) &sa, &alen); if (nsk < 0) { syslog(LOG_ERR, "Accept failed. %s(%d)", strerror(errno), errno); continue; } switch (fork()) { case 0: break; case -1: syslog(LOG_ERR, "Fork failed. %s(%d)", strerror(errno), errno); default: close(nsk); if (type == MROUTER) { close(sk); terminate = 1; } continue; } close(sk); if (msdun && ms_dun(nsk, 1, msdun) < 0) { syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno); exit(0); } ba2str(&sa.rc_bdaddr, ba); snprintf(ch, sizeof(ch), "%d", channel); /* Setup environment */ setenv("DUN_BDADDR", ba, 1); setenv("DUN_CHANNEL", ch, 1); if (!dun_open_connection(nsk, pppd, pppd_opts, 0)) syslog(LOG_INFO, "New connection from %s", ba); close(nsk); exit(0); } if (use_sdp) dun_sdp_unregister(); return 0; } /* Connect and initiate RFCOMM session * Returns: * -1 - critical error (exit persist mode) * 1 - non critical error * 0 - success */ static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter) { struct sockaddr_rc sa; int sk, err = 0, ch; if (use_cache && cache.valid && cache.channel) { /* Use cached channel */ ch = cache.channel; } else if (!channel) { syslog(LOG_INFO, "Searching for %s on %s", mrouter ? "SP" : "LAP", dst); if (dun_sdp_search(&src_addr, bdaddr, &ch, mrouter) <= 0) return 0; } else ch = channel; syslog(LOG_INFO, "Connecting to %s channel %d", dst, ch); sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sk < 0) { syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)", strerror(errno), errno); return -1; } sa.rc_family = AF_BLUETOOTH; sa.rc_channel = 0; sa.rc_bdaddr = src_addr; if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) syslog(LOG_ERR, "Bind failed. %s(%d)", strerror(errno), errno); sa.rc_channel = ch; sa.rc_bdaddr = *bdaddr; if (!connect(sk, (struct sockaddr *) &sa, sizeof(sa)) ) { if (mrouter) { sleep(1); close(sk); return 0; } syslog(LOG_INFO, "Connection established"); if (msdun && ms_dun(sk, 0, msdun) < 0) { syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno); err = 1; goto out; } if (!dun_open_connection(sk, pppd, pppd_opts, (persist > 0))) err = 0; else err = 1; } else { syslog(LOG_ERR, "Connect to %s failed. %s(%d)", dst, strerror(errno), errno); err = 1; } out: if (use_cache) { if (!err) { /* Succesesful connection, validate cache */ strcpy(cache.dst, dst); bacpy(&cache.bdaddr, bdaddr); cache.channel = ch; cache.valid = use_cache; } else { cache.channel = 0; cache.valid--; } } close(sk); return err; } /* Search and connect * Returns: * -1 - critical error (exit persist mode) * 1 - non critical error * 0 - success */ static int do_connect(void) { inquiry_info *ii; int reconnect = 0; int i, n, r = 0; do { if (reconnect) sleep(persist); reconnect = 1; if (cache.valid) { /* Use cached bdaddr */ r = create_connection(cache.dst, &cache.bdaddr, 0); if (r < 0) { terminate = 1; break; } continue; } syslog(LOG_INFO, "Inquiring"); /* FIXME: Should we use non general LAP here ? */ ii = NULL; n = hci_inquiry(src_dev, search_duration, 0, NULL, &ii, 0); if (n < 0) { syslog(LOG_ERR, "Inquiry failed. %s(%d)", strerror(errno), errno); continue; } for (i = 0; i < n; i++) { char dst[40]; ba2str(&ii[i].bdaddr, dst); r = create_connection(dst, &ii[i].bdaddr, 0); if (r < 0) { terminate = 1; break; } } bt_free(ii); } while (!terminate && persist); return r; } static void do_show(void) { dun_show_connections(); } static void do_kill(char *dst) { if (dst) { bdaddr_t ba; str2ba(dst, &ba); dun_kill_connection((void *) &ba); } else dun_kill_all_connections(); } static void sig_hup(int sig) { return; } static void sig_term(int sig) { io_cancel(); terminate = 1; } static struct option main_lopts[] = { { "help", 0, 0, 'h' }, { "listen", 0, 0, 's' }, { "connect", 1, 0, 'c' }, { "search", 2, 0, 'Q' }, { "kill", 1, 0, 'k' }, { "killall", 0, 0, 'K' }, { "channel", 1, 0, 'P' }, { "device", 1, 0, 'i' }, { "nosdp", 0, 0, 'D' }, { "list", 0, 0, 'l' }, { "show", 0, 0, 'l' }, { "nodetach", 0, 0, 'n' }, { "persist", 2, 0, 'p' }, { "auth", 0, 0, 'A' }, { "encrypt", 0, 0, 'E' }, { "secure", 0, 0, 'S' }, { "master", 0, 0, 'M' }, { "cache", 0, 0, 'C' }, { "pppd", 1, 0, 'd' }, { "msdun", 2, 0, 'X' }, { "activesync", 0, 0, 'a' }, { "mrouter", 1, 0, 'm' }, { "dialup", 0, 0, 'u' }, { 0, 0, 0, 0 } }; static const char *main_sopts = "hsc:k:Kr:i:lnp::DQ::AESMP:C::P:Xam:u"; static const char *main_help = "Bluetooth LAP (LAN Access over PPP) daemon version %s\n" "Usage:\n" "\tdund [pppd options]\n" "Options:\n" "\t--show --list -l Show active LAP connections\n" "\t--listen -s Listen for LAP connections\n" "\t--dialup -u Pretend to be a dialup/telephone\n" "\t--connect -c Create LAP connection\n" "\t--mrouter -m Create mRouter connection\n" "\t--search -Q[duration] Search and connect\n" "\t--kill -k Kill LAP connection\n" "\t--killall -K Kill all LAP connections\n" "\t--channel -P RFCOMM channel\n" "\t--device -i Source bdaddr\n" "\t--nosdp -D Disable SDP\n" "\t--auth -A Enable authentication\n" "\t--encrypt -E Enable encryption\n" "\t--secure -S Secure connection\n" "\t--master -M Become the master of a piconet\n" "\t--nodetach -n Do not become a daemon\n" "\t--persist -p[interval] Persist mode\n" "\t--pppd -d Location of the PPP daemon (pppd)\n" "\t--msdun -X[timeo] Enable Microsoft dialup networking support\n" "\t--activesync -a Enable Microsoft ActiveSync networking\n" "\t--cache -C[valid] Enable address cache\n"; int main(int argc, char *argv[]) { char *dst = NULL, *src = NULL; struct sigaction sa; int mode = NONE; int opt; while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) { switch(opt) { case 'l': mode = SHOW; detach = 0; break; case 's': mode = LISTEN; type = LANACCESS; break; case 'c': mode = CONNECT; dst = strdup(optarg); break; case 'Q': mode = CONNECT; dst = NULL; if (optarg) search_duration = atoi(optarg); break; case 'k': mode = KILL; detach = 0; dst = strdup(optarg); break; case 'K': mode = KILL; detach = 0; dst = NULL; break; case 'P': channel = atoi(optarg); break; case 'i': src = strdup(optarg); break; case 'D': use_sdp = 0; break; case 'A': auth = 1; break; case 'E': encrypt = 1; break; case 'S': secure = 1; break; case 'M': master = 1; break; case 'n': detach = 0; break; case 'p': if (optarg) persist = atoi(optarg); else persist = 5; break; case 'C': if (optarg) use_cache = atoi(optarg); else use_cache = 2; break; case 'd': pppd = strdup(optarg); break; case 'X': if (optarg) msdun = atoi(optarg); else msdun = 10; break; case 'a': msdun = 10; type = ACTIVESYNC; break; case 'm': mode = LISTEN; dst = strdup(optarg); type = MROUTER; break; case 'u': mode = LISTEN; type = DIALUP; break; case 'h': default: printf(main_help, VERSION); exit(0); } } argc -= optind; argv += optind; /* The rest is pppd options */ if (argc > 0) { for (opt = 3; argc && opt < DUN_MAX_PPP_OPTS - 1; argc--, opt++) pppd_opts[opt] = *argv++; pppd_opts[opt] = NULL; } io_init(); if (dun_init()) { free(dst); return -1; } /* Check non daemon modes first */ switch (mode) { case SHOW: do_show(); free(dst); return 0; case KILL: do_kill(dst); free(dst); return 0; case NONE: printf(main_help, VERSION); free(dst); return 0; } /* Initialize signals */ memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = sig_hup; sigaction(SIGHUP, &sa, NULL); if (detach && daemon(0, 0)) { perror("Can't start daemon"); exit(1); } openlog("dund", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON); syslog(LOG_INFO, "Bluetooth DUN daemon version %s", VERSION); if (src) { src_dev = hci_devid(src); if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) { syslog(LOG_ERR, "Invalid source. %s(%d)", strerror(errno), errno); free(dst); return -1; } } if (dst) { strncpy(cache.dst, dst, sizeof(cache.dst) - 1); str2ba(dst, &cache.bdaddr); /* Disable cache invalidation */ use_cache = cache.valid = ~0; } switch (mode) { case CONNECT: do_connect(); break; case LISTEN: do_listen(); break; } free(dst); return 0; } bluez-4.101/compat/dund.10000644000000000000000000000277511071665350012045 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29. .TH BlueZ "1" "February 2003" "DUN daemon" "User Commands" .SH NAME dund \- BlueZ Bluetooth dial-up networking daemon .SH DESCRIPTION DUN daemon .SH SYNOPSIS dund [pppd options] .SH OPTIONS .TP \fB\-\-show\fR \fB\-\-list\fR \fB\-l\fR Show active DUN connections .TP \fB\-\-listen\fR \fB\-s\fR Listen for DUN connections .TP \fB\-\-dialup\fR \fB\-u\fR Listen for dialup/telephone connections .TP \fB\-\-connect\fR \fB\-c\fR Create DUN connection .TP \fB\-\-mrouter\fR \fB\-m\fR Create mRouter connection .TP \fB\-\-search\fR \fB\-Q[duration]\fR Search and connect .TP \fB\-\-kill\fR \fB\-k\fR Kill DUN connection .TP \fB\-\-killall\fR \fB\-K\fR Kill all DUN connections .TP \fB\-\-channel\fR \fB\-C\fR RFCOMM channel .TP \fB\-\-device\fR \fB\-i\fR Source bdaddr .TP \fB\-\-nosdp\fR \fB\-D\fR Disable SDP .TP \fB\-\-auth\fR \fB\-A\fR Enable authentification .TP \fB\-\-encrypt\fR \fB\-E\fR Enable encryption .TP \fB\-\-secure\fR \fB\-S\fR Secure connection .TP \fB\-\-master\fR \fB\-M\fR Become the master of a piconet .TP \fB\-\-nodetach\fR \fB\-n\fR Do not become a daemon .TP \fB\-\-persist\fR \fB\-p[interval]\fR Persist mode .TP \fB\-\-pppd\fR \fB\-d\fR Location of the PPP daemon (pppd) .TP \fB\-\-msdun\fR \fB\-X\fR [timeo] Enable Microsoft dialup networking support .TP \fB\-\-activesync\fR \fB\-a\fR Enable Microsoft ActiveSync networking .TP \fB\-\-cache\fR \fB\-C\fR [valid] Enable address cache bluez-4.101/compat/dund.h0000644000000000000000000000242711376221745012132 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #define DUN_CONFIG_DIR "/etc/bluetooth/dun" #define DUN_DEFAULT_CHANNEL 1 #define DUN_MAX_PPP_OPTS 40 int dun_init(void); int dun_cleanup(void); int dun_show_connections(void); int dun_kill_connection(uint8_t *dst); int dun_kill_all_connections(void); int dun_open_connection(int sk, char *pppd, char **pppd_opts, int wait); int ms_dun(int fd, int server, int timeo); bluez-4.101/compat/msdun.c0000644000000000000000000000536211376221745012322 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include "lib.h" #include "dund.h" #define MS_PPP 2 #define MS_SUCCESS 1 #define MS_FAILED -1 #define MS_TIMEOUT -2 static sigjmp_buf jmp; static int retry; static int timeout; static void sig_alarm(int sig) { siglongjmp(jmp, MS_TIMEOUT); } static int w4_str(int fd, char *str) { char buf[40]; unsigned len = 0; int r; while (1) { r = read(fd, buf + len, sizeof(buf) - len - 1); if (r < 0) { if (errno == EINTR || errno == EAGAIN) continue; break; } if (!r) break; len += r; if (len < strlen(str)) continue; buf[len] = 0; if (strstr(buf, str)) return MS_SUCCESS; /* Detect PPP */ if (strchr(buf, '~')) return MS_PPP; } return MS_FAILED; } static int ms_server(int fd) { switch (w4_str(fd, "CLIENT")) { case MS_SUCCESS: write_n(fd, "CLIENTSERVER", 12); case MS_PPP: return MS_SUCCESS; default: return MS_FAILED; } } static int ms_client(int fd) { write_n(fd, "CLIENT", 6); return w4_str(fd, "CLIENTSERVER"); } int ms_dun(int fd, int server, int timeo) { sig_t osig; retry = 4; timeout = timeo; if (!server) timeout /= retry; osig = signal(SIGALRM, sig_alarm); while (1) { int r = sigsetjmp(jmp, 1); if (r) { if (r == MS_TIMEOUT && !server && --retry) continue; alarm(0); signal(SIGALRM, osig); switch (r) { case MS_SUCCESS: case MS_PPP: errno = 0; return 0; case MS_FAILED: errno = EPROTO; break; case MS_TIMEOUT: errno = ETIMEDOUT; break; } return -1; } alarm(timeout); if (server) r = ms_server(fd); else r = ms_client(fd); siglongjmp(jmp, r); } } bluez-4.101/compat/pand.h0000644000000000000000000000243111376221745012115 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2002-2003 Maxim Krasnyansky * Copyright (C) 2002-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ int bnep_init(void); int bnep_cleanup(void); int bnep_str2svc(char *svc, uint16_t *uuid); char *bnep_svc2str(uint16_t uuid); int bnep_show_connections(void); int bnep_kill_connection(uint8_t *dst); int bnep_kill_all_connections(void); int bnep_accept_connection(int sk, uint16_t role, char *dev); int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev); bluez-4.101/compat/fakehid.c0000644000000000000000000003163211571052274012562 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include "hidd.h" #include "uinput.h" #include #ifdef NEED_PPOLL #include "ppoll.h" #endif static volatile sig_atomic_t __io_canceled = 0; static void sig_hup(int sig) { } static void sig_term(int sig) { __io_canceled = 1; } static int send_event(int fd, uint16_t type, uint16_t code, int32_t value) { struct uinput_event event; if (fd <= fileno(stderr)) return -EINVAL; memset(&event, 0, sizeof(event)); event.type = type; event.code = code; event.value = value; return write(fd, &event, sizeof(event)); } static int uinput_create(char *name, int keyboard, int mouse) { struct uinput_dev dev; int fd, aux; fd = open("/dev/uinput", O_RDWR); if (fd < 0) { fd = open("/dev/input/uinput", O_RDWR); if (fd < 0) { fd = open("/dev/misc/uinput", O_RDWR); if (fd < 0) { fprintf(stderr, "Can't open input device: %s (%d)\n", strerror(errno), errno); return -1; } } } memset(&dev, 0, sizeof(dev)); if (name) strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1); dev.id.bustype = BUS_BLUETOOTH; dev.id.vendor = 0x0000; dev.id.product = 0x0000; dev.id.version = 0x0000; if (write(fd, &dev, sizeof(dev)) < 0) { fprintf(stderr, "Can't write device information: %s (%d)\n", strerror(errno), errno); close(fd); return -1; } if (mouse) { ioctl(fd, UI_SET_EVBIT, EV_REL); for (aux = REL_X; aux <= REL_MISC; aux++) ioctl(fd, UI_SET_RELBIT, aux); } if (keyboard) { ioctl(fd, UI_SET_EVBIT, EV_KEY); ioctl(fd, UI_SET_EVBIT, EV_LED); ioctl(fd, UI_SET_EVBIT, EV_REP); for (aux = KEY_RESERVED; aux <= KEY_UNKNOWN; aux++) ioctl(fd, UI_SET_KEYBIT, aux); /* *for (aux = LED_NUML; aux <= LED_MISC; aux++) * ioctl(fd, UI_SET_LEDBIT, aux); */ } if (mouse) { ioctl(fd, UI_SET_EVBIT, EV_KEY); for (aux = BTN_LEFT; aux <= BTN_BACK; aux++) ioctl(fd, UI_SET_KEYBIT, aux); } ioctl(fd, UI_DEV_CREATE); return fd; } static int rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) { struct sockaddr_rc addr; int sk; sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM); if (sk < 0) { fprintf(stderr, "Can't create socket: %s (%d)\n", strerror(errno), errno); return -1; } memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, src); if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { fprintf(stderr, "Can't bind socket: %s (%d)\n", strerror(errno), errno); close(sk); return -1; } memset(&addr, 0, sizeof(addr)); addr.rc_family = AF_BLUETOOTH; bacpy(&addr.rc_bdaddr, dst); addr.rc_channel = channel; if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { fprintf(stderr, "Can't connect: %s (%d)\n", strerror(errno), errno); close(sk); return -1; } return sk; } static void func(int fd) { } static void back(int fd) { } static void next(int fd) { } static void button(int fd, unsigned int button, int is_press) { switch (button) { case 1: send_event(fd, EV_KEY, BTN_LEFT, is_press); break; case 3: send_event(fd, EV_KEY, BTN_RIGHT, is_press); break; } send_event(fd, EV_SYN, SYN_REPORT, 0); } static void move(int fd, unsigned int direction) { double angle; int32_t x, y; angle = (direction * 22.5) * 3.1415926 / 180; x = (int) (sin(angle) * 8); y = (int) (cos(angle) * -8); send_event(fd, EV_REL, REL_X, x); send_event(fd, EV_REL, REL_Y, y); send_event(fd, EV_SYN, SYN_REPORT, 0); } static inline void epox_decode(int fd, unsigned char event) { switch (event) { case 48: func(fd); break; case 55: back(fd); break; case 56: next(fd); break; case 53: button(fd, 1, 1); break; case 121: button(fd, 1, 0); break; case 113: break; case 54: button(fd, 3, 1); break; case 120: button(fd, 3, 0); break; case 112: break; case 51: move(fd, 0); break; case 97: move(fd, 1); break; case 65: move(fd, 2); break; case 98: move(fd, 3); break; case 50: move(fd, 4); break; case 99: move(fd, 5); break; case 67: move(fd, 6); break; case 101: move(fd, 7); break; case 52: move(fd, 8); break; case 100: move(fd, 9); break; case 66: move(fd, 10); break; case 102: move(fd, 11); break; case 49: move(fd, 12); break; case 103: move(fd, 13); break; case 57: move(fd, 14); break; case 104: move(fd, 15); break; case 69: break; default: printf("Unknown event code %d\n", event); break; } } int epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) { unsigned char buf[16]; struct sigaction sa; struct pollfd p; sigset_t sigs; char addr[18]; int i, fd, sk, len; sk = rfcomm_connect(src, dst, channel); if (sk < 0) return -1; fd = uinput_create("Bluetooth Presenter", 0, 1); if (fd < 0) { close(sk); return -1; } ba2str(dst, addr); printf("Connected to %s on channel %d\n", addr, channel); printf("Press CTRL-C for hangup\n"); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = sig_hup; sigaction(SIGHUP, &sa, NULL); sigfillset(&sigs); sigdelset(&sigs, SIGCHLD); sigdelset(&sigs, SIGPIPE); sigdelset(&sigs, SIGTERM); sigdelset(&sigs, SIGINT); sigdelset(&sigs, SIGHUP); p.fd = sk; p.events = POLLIN | POLLERR | POLLHUP; while (!__io_canceled) { p.revents = 0; if (ppoll(&p, 1, NULL, &sigs) < 1) continue; len = read(sk, buf, sizeof(buf)); if (len < 0) break; for (i = 0; i < len; i++) epox_decode(fd, buf[i]); } printf("Disconnected\n"); ioctl(fd, UI_DEV_DESTROY); close(fd); close(sk); return 0; } int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) { printf("Not implemented\n"); return -1; } /* The strange meta key close to Ctrl has been assigned to Esc, Fn key to CtrlR and the left space to Alt*/ static unsigned char jthree_keycodes[63] = { KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T, KEY_A, KEY_S, KEY_D, KEY_F, KEY_G, KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B, KEY_LEFTALT, KEY_TAB, KEY_CAPSLOCK, KEY_ESC, KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE, KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE, KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER, KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_UP, KEY_SPACE, KEY_COMPOSE, KEY_LEFT, KEY_DOWN, KEY_RIGHT, KEY_LEFTCTRL, KEY_RIGHTSHIFT, KEY_LEFTSHIFT, KEY_DELETE, KEY_RIGHTCTRL, KEY_RIGHTALT, }; static inline void jthree_decode(int fd, unsigned char event) { if (event > 63) send_event(fd, EV_KEY, jthree_keycodes[event & 0x3f], 0); else send_event(fd, EV_KEY, jthree_keycodes[event - 1], 1); } int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) { unsigned char buf[16]; struct sigaction sa; struct pollfd p; sigset_t sigs; char addr[18]; int i, fd, sk, len; sk = rfcomm_connect(src, dst, channel); if (sk < 0) return -1; fd = uinput_create("J-Three Keyboard", 1, 0); if (fd < 0) { close(sk); return -1; } ba2str(dst, addr); printf("Connected to %s on channel %d\n", addr, channel); printf("Press CTRL-C for hangup\n"); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = sig_hup; sigaction(SIGHUP, &sa, NULL); sigfillset(&sigs); sigdelset(&sigs, SIGCHLD); sigdelset(&sigs, SIGPIPE); sigdelset(&sigs, SIGTERM); sigdelset(&sigs, SIGINT); sigdelset(&sigs, SIGHUP); p.fd = sk; p.events = POLLIN | POLLERR | POLLHUP; while (!__io_canceled) { p.revents = 0; if (ppoll(&p, 1, NULL, &sigs) < 1) continue; len = read(sk, buf, sizeof(buf)); if (len < 0) break; for (i = 0; i < len; i++) jthree_decode(fd, buf[i]); } printf("Disconnected\n"); ioctl(fd, UI_DEV_DESTROY); close(fd); close(sk); return 0; } static const int celluon_xlate_num[10] = { KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9 }; static const int celluon_xlate_char[26] = { KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z }; static int celluon_xlate(int c) { if (c >= '0' && c <= '9') return celluon_xlate_num[c - '0']; if (c >= 'A' && c <= 'Z') return celluon_xlate_char[c - 'A']; switch (c) { case 0x08: return KEY_BACKSPACE; case 0x09: return KEY_TAB; case 0x0d: return KEY_ENTER; case 0x11: return KEY_LEFTCTRL; case 0x14: return KEY_CAPSLOCK; case 0x20: return KEY_SPACE; case 0x25: return KEY_LEFT; case 0x26: return KEY_UP; case 0x27: return KEY_RIGHT; case 0x28: return KEY_DOWN; case 0x2e: return KEY_DELETE; case 0x5b: return KEY_MENU; case 0xa1: return KEY_RIGHTSHIFT; case 0xa0: return KEY_LEFTSHIFT; case 0xba: return KEY_SEMICOLON; case 0xbd: return KEY_MINUS; case 0xbc: return KEY_COMMA; case 0xbb: return KEY_EQUAL; case 0xbe: return KEY_DOT; case 0xbf: return KEY_SLASH; case 0xc0: return KEY_GRAVE; case 0xdb: return KEY_LEFTBRACE; case 0xdc: return KEY_BACKSLASH; case 0xdd: return KEY_RIGHTBRACE; case 0xde: return KEY_APOSTROPHE; case 0xff03: return KEY_HOMEPAGE; case 0xff04: return KEY_TIME; case 0xff06: return KEY_OPEN; case 0xff07: return KEY_LIST; case 0xff08: return KEY_MAIL; case 0xff30: return KEY_CALC; case 0xff1a: /* Map FN to ALT */ return KEY_LEFTALT; case 0xff2f: return KEY_INFO; default: printf("Unknown key %x\n", c); return c; } } struct celluon_state { int len; /* Expected length of current packet */ int count; /* Number of bytes received */ int action; int key; }; static void celluon_decode(int fd, struct celluon_state *s, uint8_t c) { if (s->count < 2 && c != 0xa5) { /* Lost Sync */ s->count = 0; return; } switch (s->count) { case 0: /* New packet - Reset state */ s->len = 30; s->key = 0; break; case 1: break; case 6: s->action = c; break; case 28: s->key = c; if (c == 0xff) s->len = 31; break; case 29: case 30: if (s->count == s->len - 1) { /* TODO: Verify checksum */ if (s->action < 2) { send_event(fd, EV_KEY, celluon_xlate(s->key), s->action); } s->count = -1; } else { s->key = (s->key << 8) | c; } break; } s->count++; return; } int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel) { unsigned char buf[16]; struct sigaction sa; struct pollfd p; sigset_t sigs; char addr[18]; int i, fd, sk, len; struct celluon_state s; sk = rfcomm_connect(src, dst, channel); if (sk < 0) return -1; fd = uinput_create("Celluon Keyboard", 1, 0); if (fd < 0) { close(sk); return -1; } ba2str(dst, addr); printf("Connected to %s on channel %d\n", addr, channel); printf("Press CTRL-C for hangup\n"); memset(&sa, 0, sizeof(sa)); sa.sa_flags = SA_NOCLDSTOP; sa.sa_handler = SIG_IGN; sigaction(SIGCHLD, &sa, NULL); sigaction(SIGPIPE, &sa, NULL); sa.sa_handler = sig_term; sigaction(SIGTERM, &sa, NULL); sigaction(SIGINT, &sa, NULL); sa.sa_handler = sig_hup; sigaction(SIGHUP, &sa, NULL); sigfillset(&sigs); sigdelset(&sigs, SIGCHLD); sigdelset(&sigs, SIGPIPE); sigdelset(&sigs, SIGTERM); sigdelset(&sigs, SIGINT); sigdelset(&sigs, SIGHUP); p.fd = sk; p.events = POLLIN | POLLERR | POLLHUP; memset(&s, 0, sizeof(s)); while (!__io_canceled) { p.revents = 0; if (ppoll(&p, 1, NULL, &sigs) < 1) continue; len = read(sk, buf, sizeof(buf)); if (len < 0) break; for (i = 0; i < len; i++) celluon_decode(fd, &s, buf[i]); } printf("Disconnected\n"); ioctl(fd, UI_DEV_DESTROY); close(fd); close(sk); return 0; } bluez-4.101/compat/sdp.c0000644000000000000000000004221211766125764011764 00000000000000/* * * BlueZ - Bluetooth protocol stack for Linux * * Copyright (C) 2003-2010 Marcel Holtmann * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "textfile.h" #include "sdp.h" static sdp_record_t *record = NULL; static sdp_session_t *session = NULL; static void epox_endian_quirk(unsigned char *data, int size) { /* USAGE_PAGE (Keyboard) 05 07 * USAGE_MINIMUM (0) 19 00 * USAGE_MAXIMUM (65280) 2A 00 FF <= must be FF 00 * LOGICAL_MINIMUM (0) 15 00 * LOGICAL_MAXIMUM (65280) 26 00 FF <= must be FF 00 */ unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff, 0x15, 0x00, 0x26, 0x00, 0xff }; unsigned int i; if (!data) return; for (i = 0; i < size - sizeof(pattern); i++) { if (!memcmp(data + i, pattern, sizeof(pattern))) { data[i + 5] = 0xff; data[i + 6] = 0x00; data[i + 10] = 0xff; data[i + 11] = 0x00; } } } static int store_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) { char filename[PATH_MAX + 1], addr[18], *str, *desc; int i, err, size; ba2str(src, addr); create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2; str = malloc(size); if (!str) return -ENOMEM; desc = malloc((req->rd_size * 2) + 1); if (!desc) { free(str); return -ENOMEM; } memset(desc, 0, (req->rd_size * 2) + 1); for (i = 0; i < req->rd_size; i++) sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]); snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s", req->vendor, req->product, req->version, req->subclass, req->country, req->parser, desc, req->flags, req->name); free(desc); create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); ba2str(dst, addr); err = textfile_put(filename, addr, str); free(str); return err; } int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) { char filename[PATH_MAX + 1], addr[18], tmp[3], *str, *desc; unsigned int vendor, product, version, subclass, country, parser, pos; int i; desc = malloc(4096); if (!desc) return -ENOMEM; memset(desc, 0, 4096); ba2str(src, addr); create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd"); ba2str(dst, addr); str = textfile_get(filename, addr); if (!str) { free(desc); return -EIO; } sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n", &vendor, &product, &version, &subclass, &country, &parser, desc, &req->flags, &pos); req->vendor = vendor; req->product = product; req->version = version; req->subclass = subclass; req->country = country; req->parser = parser; snprintf(req->name, 128, "%s", str + pos); free(str); req->rd_size = strlen(desc) / 2; req->rd_data = malloc(req->rd_size); if (!req->rd_data) { free(desc); return -ENOMEM; } memset(tmp, 0, sizeof(tmp)); for (i = 0; i < req->rd_size; i++) { memcpy(tmp, desc + (i * 2), 2); req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16); } free(desc); return 0; } int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req) { struct sockaddr_l2 addr; socklen_t addrlen; bdaddr_t bdaddr; uint32_t range = 0x0000ffff; sdp_session_t *s; sdp_list_t *search, *attrid, *pnp_rsp, *hid_rsp; sdp_record_t *rec; sdp_data_t *pdlist, *pdlist2; uuid_t svclass; int err; s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE); if (!s) return -1; sdp_uuid16_create(&svclass, PNP_INFO_SVCLASS_ID); search = sdp_list_append(NULL, &svclass); attrid = sdp_list_append(NULL, &range); err = sdp_service_search_attr_req(s, search, SDP_ATTR_REQ_RANGE, attrid, &pnp_rsp); sdp_list_free(search, NULL); sdp_list_free(attrid, NULL); sdp_uuid16_create(&svclass, HID_SVCLASS_ID); search = sdp_list_append(NULL, &svclass); attrid = sdp_list_append(NULL, &range); err = sdp_service_search_attr_req(s, search, SDP_ATTR_REQ_RANGE, attrid, &hid_rsp); sdp_list_free(search, NULL); sdp_list_free(attrid, NULL); memset(&addr, 0, sizeof(addr)); addrlen = sizeof(addr); if (getsockname(s->sock, (struct sockaddr *) &addr, &addrlen) < 0) bacpy(&bdaddr, src); else bacpy(&bdaddr, &addr.l2_bdaddr); sdp_close(s); if (err || !hid_rsp) return -1; if (pnp_rsp) { rec = (sdp_record_t *) pnp_rsp->data; pdlist = sdp_data_get(rec, 0x0201); req->vendor = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, 0x0202); req->product = pdlist ? pdlist->val.uint16 : 0x0000; pdlist = sdp_data_get(rec, 0x0203); req->version = pdlist ? pdlist->val.uint16 : 0x0000; sdp_record_free(rec); } rec = (sdp_record_t *) hid_rsp->data; pdlist2 = sdp_data_get(rec, 0x0100); if (pdlist2) strncpy(req->name, pdlist2->val.str, sizeof(req->name) - 1); else { pdlist = sdp_data_get(rec, 0x0101); pdlist2 = sdp_data_get(rec, 0x0102); if (pdlist) { if (pdlist2) { if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) { strncpy(req->name, pdlist2->val.str, sizeof(req->name) - 1); strcat(req->name, " "); } strncat(req->name, pdlist->val.str, sizeof(req->name) - strlen(req->name)); } else strncpy(req->name, pdlist->val.str, sizeof(req->name) - 1); } } pdlist = sdp_data_get(rec, 0x0201); req->parser = pdlist ? pdlist->val.uint16 : 0x0100; pdlist = sdp_data_get(rec, 0x0202); req->subclass = pdlist ? pdlist->val.uint8 : 0; pdlist = sdp_data_get(rec, 0x0203); req->country = pdlist ? pdlist->val.uint8 : 0; pdlist = sdp_data_get(rec, 0x0206); if (pdlist) { pdlist = pdlist->val.dataseq; pdlist = pdlist->val.dataseq; pdlist = pdlist->next; req->rd_data = malloc(pdlist->unitSize); if (req->rd_data) { memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize); req->rd_size = pdlist->unitSize; epox_endian_quirk(req->rd_data, req->rd_size); } } sdp_record_free(rec); if (bacmp(&bdaddr, BDADDR_ANY)) store_device_info(&bdaddr, dst, req); return 0; } int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len) { uint16_t attr1 = SDP_ATTR_PROTO_DESC_LIST; uint16_t attr2 = SDP_ATTR_SVCNAME_PRIMARY; sdp_session_t *s; sdp_list_t *search, *attrid, *rsp; uuid_t svclass; int err; s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE); if (!s) return -1; sdp_uuid16_create(&svclass, HEADSET_SVCLASS_ID); search = sdp_list_append(NULL, &svclass); attrid = sdp_list_append(NULL, &attr1); attrid = sdp_list_append(attrid, &attr2); err = sdp_service_search_attr_req(s, search, SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp); sdp_list_free(search, NULL); sdp_list_free(attrid, NULL); if (err <= 0) { sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID); search = sdp_list_append(NULL, &svclass); attrid = sdp_list_append(NULL, &attr1); attrid = sdp_list_append(attrid, &attr2); err = sdp_service_search_attr_req(s, search, SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp); sdp_list_free(search, NULL); sdp_list_free(attrid, NULL); if (err < 0) { sdp_close(s); return err; } if (uuid) *uuid = SERIAL_PORT_SVCLASS_ID; } else { if (uuid) *uuid = HEADSET_SVCLASS_ID; } sdp_close(s); for (; rsp; rsp = rsp->next) { sdp_record_t *rec = (sdp_record_t *) rsp->data; sdp_list_t *protos; sdp_get_service_name(rec, name, len); if (!sdp_get_access_protos(rec, &protos)) { uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID); if (ch > 0) { if (channel) *channel = ch; return 0; } } sdp_record_free(rec); } return -EIO; } void bnep_sdp_unregister(void) { if (record && sdp_record_unregister(session, record)) syslog(LOG_ERR, "Service record unregistration failed."); sdp_close(session); } int bnep_sdp_register(bdaddr_t *device, uint16_t role) { sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto; uuid_t root_uuid, pan, l2cap, bnep; sdp_profile_desc_t profile[1]; sdp_list_t *proto[2]; sdp_data_t *v, *p; uint16_t psm = 15, version = 0x0100; uint16_t security_desc = 0; uint16_t net_access_type = 0xfffe; uint32_t max_net_access_rate = 0; char *name = "BlueZ PAN"; char *desc = "BlueZ PAN Service"; int status; session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0); if (!session) { syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)", strerror(errno), errno); return -1; } record = sdp_record_alloc(); if (!record) { syslog(LOG_ERR, "Failed to allocate service record %s(%d)", strerror(errno), errno); sdp_close(session); return -1; } sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_list_free(root, 0); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); p = sdp_data_alloc(SDP_UINT16, &psm); proto[0] = sdp_list_append(proto[0], p); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&bnep, BNEP_UUID); proto[1] = sdp_list_append(NULL, &bnep); v = sdp_data_alloc(SDP_UINT16, &version); proto[1] = sdp_list_append(proto[1], v); /* Supported protocols */ { uint16_t ptype[4] = { 0x0800, /* IPv4 */ 0x0806, /* ARP */ }; sdp_data_t *head, *pseq; int p; for (p = 0, head = NULL; p < 2; p++) { sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]); if (head) sdp_seq_append(head, data); else head = data; } pseq = sdp_data_alloc(SDP_SEQ16, head); proto[1] = sdp_list_append(proto[1], pseq); } apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); sdp_add_lang_attr(record); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(apseq, NULL); sdp_list_free(aproto, NULL); sdp_data_free(p); sdp_data_free(v); sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC, SDP_UINT16, &security_desc); switch (role) { case BNEP_SVC_NAP: sdp_uuid16_create(&pan, NAP_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_set_info_attr(record, "Network Access Point", name, desc); sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE, SDP_UINT16, &net_access_type); sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE, SDP_UINT32, &max_net_access_rate); break; case BNEP_SVC_GN: sdp_uuid16_create(&pan, GN_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_set_info_attr(record, "Group Network Service", name, desc); break; case BNEP_SVC_PANU: sdp_uuid16_create(&pan, PANU_SVCLASS_ID); svclass = sdp_list_append(NULL, &pan); sdp_set_service_classes(record, svclass); sdp_list_free(svclass, 0); sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_list_free(pfseq, 0); sdp_set_info_attr(record, "PAN User", name, desc); break; } status = sdp_device_record_register(session, device, record, 0); if (status) { syslog(LOG_ERR, "SDP registration failed."); sdp_record_free(record); record = NULL; sdp_close(session); return -1; } return 0; } /* Search for PAN service. * Returns 1 if service is found and 0 otherwise. */ int bnep_sdp_search(bdaddr_t *src, bdaddr_t *dst, uint16_t service) { sdp_list_t *srch, *rsp = NULL; sdp_session_t *s; uuid_t svclass; int err; switch (service) { case BNEP_SVC_PANU: sdp_uuid16_create(&svclass, PANU_SVCLASS_ID); break; case BNEP_SVC_NAP: sdp_uuid16_create(&svclass, NAP_SVCLASS_ID); break; case BNEP_SVC_GN: sdp_uuid16_create(&svclass, GN_SVCLASS_ID); break; } srch = sdp_list_append(NULL, &svclass); s = sdp_connect(src, dst, 0); if (!s) { syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)", strerror(errno), errno); return 0; } err = sdp_service_search_req(s, srch, 1, &rsp); sdp_close(s); /* Assume that search is successeful * if at least one record is found */ if (!err && sdp_list_len(rsp)) return 1; return 0; } static unsigned char async_uuid[] = { 0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62, 0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C }; void dun_sdp_unregister(void) { if (record && sdp_record_unregister(session, record)) syslog(LOG_ERR, "Service record unregistration failed."); sdp_close(session); } int dun_sdp_register(bdaddr_t *device, uint8_t channel, int type) { sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto; uuid_t root_uuid, l2cap, rfcomm, dun; sdp_profile_desc_t profile[1]; sdp_list_t *proto[2]; int status; session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0); if (!session) { syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)", strerror(errno), errno); return -1; } record = sdp_record_alloc(); if (!record) { syslog(LOG_ERR, "Failed to alloc service record"); return -1; } sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&l2cap, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&rfcomm, RFCOMM_UUID); proto[1] = sdp_list_append(NULL, &rfcomm); proto[1] = sdp_list_append(proto[1], sdp_data_alloc(SDP_UINT8, &channel)); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); switch (type) { case MROUTER: sdp_uuid16_create(&dun, SERIAL_PORT_SVCLASS_ID); break; case ACTIVESYNC: sdp_uuid128_create(&dun, (void *) async_uuid); break; case DIALUP: sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID); break; default: sdp_uuid16_create(&dun, LAN_ACCESS_SVCLASS_ID); break; } svclass = sdp_list_append(NULL, &dun); sdp_set_service_classes(record, svclass); switch (type) { case LANACCESS: sdp_uuid16_create(&profile[0].uuid, LAN_ACCESS_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); break; case DIALUP: sdp_uuid16_create(&profile[0].uuid, DIALUP_NET_PROFILE_ID); profile[0].version = 0x0100; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); break; } switch (type) { case MROUTER: sdp_set_info_attr(record, "mRouter", NULL, NULL); break; case ACTIVESYNC: sdp_set_info_attr(record, "ActiveSync", NULL, NULL); break; case DIALUP: sdp_set_info_attr(record, "Dialup Networking", NULL, NULL); break; default: sdp_set_info_attr(record, "LAN Access Point", NULL, NULL); break; } status = sdp_device_record_register(session, device, record, 0); if (status) { syslog(LOG_ERR, "SDP registration failed."); sdp_record_free(record); record = NULL; return -1; } return 0; } int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel, int type) { sdp_session_t *s; sdp_list_t *srch, *attrs, *rsp; uuid_t svclass; uint16_t attr; int err; s = sdp_connect(src, dst, 0); if (!s) { syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)", strerror(errno), errno); return -1; } switch (type) { case MROUTER: sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID); break; case ACTIVESYNC: sdp_uuid128_create(&svclass, (void *) async_uuid); break; case DIALUP: sdp_uuid16_create(&svclass, DIALUP_NET_SVCLASS_ID); break; default: sdp_uuid16_create(&svclass, LAN_ACCESS_SVCLASS_ID); break; } srch = sdp_list_append(NULL, &svclass); attr = SDP_ATTR_PROTO_DESC_LIST; attrs = sdp_list_append(NULL, &attr); err = sdp_service_search_attr_req(s, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp); sdp_close(s); if (err) return 0; for(; rsp; rsp = rsp->next) { sdp_record_t *rec = (sdp_record_t *) rsp->data; sdp_list_t *protos; if (!sdp_get_access_protos(rec, &protos)) { int ch = sdp_get_proto_port(protos, RFCOMM_UUID); if (ch > 0) { *channel = ch; return 1; } } } return 0; } bluez-4.101/compat/pand.10000644000000000000000000000330711071665350012025 00000000000000.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.29. .TH BlueZ "1" "February 2003" "PAN daemon" "User Commands" .SH NAME pand \- BlueZ Bluetooth PAN daemon .SH DESCRIPTION The pand PAN daemon allows your computer to connect to ethernet networks using Bluetooth. .SH SYNPOSIS pand .SH OPTIONS .TP \fB\-\-show\fR \fB\-\-list\fR \fB\-l\fR Show active PAN connections .TP \fB\-\-listen\fR \fB\-s\fR Listen for PAN connections .TP \fB\-\-connect\fR \fB\-c\fR Create PAN connection .TP \fB\-\-search\fR \fB\-Q[duration]\fR Search and connect .TP \fB\-\-kill\fR \fB\-k\fR Kill PAN connection .TP \fB\-\-killall\fR \fB\-K\fR Kill all PAN connections .TP \fB\-\-role\fR \fB\-r\fR Local PAN role (PANU, NAP, GN) .TP \fB\-\-service\fR \fB\-d\fR Remote PAN service (PANU, NAP, GN) .TP \fB\-\-ethernet\fR \fB\-e\fR Network interface name .TP \fB\-\-device\fR \fB\-i\fR Source bdaddr .TP \fB\-\-nosdp\fR \fB\-D\fR Disable SDP .TP \fB\-\-encrypt\fR \fB\-E\fR Enable encryption .TP \fB\-\-secure\fR \fB\-S\fR Secure connection .TP \fB\-\-master\fR \fB\-M\fR Become the master of a piconet .TP \fB\-\-nodetach\fR \fB\-n\fR Do not become a daemon .TP \fB\-\-persist\fR \fB\-p[interval]\fR Persist mode .TP \fB\-\-cache\fR \fB\-C[valid]\fR Cache addresses .TP \fB\-\-pidfile\fR \fB\-P \fR Create PID file .TP \fB\-\-devup\fR \fB\-u