doc: Update all docs to 1.9. Note this in doc/RELNOTES
[fw/altos] / libaltos / libaltos_linux.c
index d7cd15cfe79357a92b7f44c680c9b8bb6038ca4a..255b977347296078d66bf31220cd742e542cbd78 100644 (file)
@@ -3,7 +3,8 @@
  *
  * 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; version 2 of the License.
+ * 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
@@ -25,6 +26,8 @@
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
 #include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
 
 static char *
 cc_fullname (char *dir, char *file)
@@ -379,6 +382,30 @@ bt_func(hci_get_route, int, -1, (bdaddr_t *bdaddr), (bdaddr))
 bt_func(hci_inquiry, int, -1, (int adapter_id, int len, int max_rsp, const uint8_t *lap, inquiry_info **devs, long flags), (adapter_id, len, max_rsp, lap, devs, flags))
 #define hci_inquiry altos_hci_inquiry
 
+bt_func(sdp_connect, sdp_session_t *, 0, (const bdaddr_t *src, const bdaddr_t *dst, uint32_t flags), (src, dst, flags))
+#define sdp_connect altos_sdp_connect
+
+bt_func(sdp_uuid16_create, uuid_t *, 0, (uuid_t *uuid, uint16_t data), (uuid, data))
+#define sdp_uuid16_create altos_sdp_uuid16_create
+
+bt_func(sdp_list_append, sdp_list_t *, 0, (sdp_list_t *list, void *d), (list, d))
+#define sdp_list_append altos_sdp_list_append
+
+bt_func(sdp_service_search_attr_req, int, -1, (sdp_session_t *session, const sdp_list_t *search, sdp_attrreq_type_t reqtype, const sdp_list_t *attrid_list, sdp_list_t **rsp_list), (session, search, reqtype, attrid_list, rsp_list))
+#define sdp_service_search_attr_req altos_sdp_service_search_attr_req
+
+bt_func(sdp_uuid_to_proto, int, 0, (uuid_t *uuid), (uuid))
+#define sdp_uuid_to_proto altos_sdp_uuid_to_proto
+
+bt_func(sdp_get_access_protos, int, 0, (const sdp_record_t *rec, sdp_list_t **protos), (rec, protos))
+#define sdp_get_access_protos altos_sdp_get_access_protos
+
+bt_func(sdp_get_proto_port, int, 0, (const sdp_list_t *list, int proto), (list, proto))
+#define sdp_get_proto_port altos_sdp_get_proto_port
+
+bt_func(sdp_close, int, 0, (sdp_session_t *session), (session))
+#define sdp_close altos_sdp_close
+
 struct altos_bt_list {
        inquiry_info    *ii;
        int             sock;
@@ -477,7 +504,68 @@ altos_bt_open(struct altos_bt_device *device)
        struct sockaddr_rc      addr = { 0 };
        int                     status, i;
        struct altos_file_posix *file;
+       sdp_session_t           *session = NULL;
+       int                     channel = 0;
 
+       if (str2ba(device->addr, &addr.rc_bdaddr) < 0) {
+               altos_set_last_posix_error();
+               goto no_file;
+       }
+
+#if 0
+       /*
+        * Search for the RFCOMM service to get the right channel
+        */
+       session = sdp_connect(BDADDR_ANY, &addr.rc_bdaddr, SDP_RETRY_IF_BUSY);
+
+       if (session) {
+               static const uint8_t svc_uuid_int[] = {
+                       0, 0, 0, 0, 0, 0, 0, 0,
+                       0, 0, 0, 0, 0, 0, 0x11, 0x01
+               };
+               int                     err;
+               uuid_t                  svc_uuid;
+               uint32_t                range;
+               sdp_list_t              *search_list, *attrid_list;
+               sdp_list_t              *response_list = NULL, *r;
+               sdp_uuid16_create(&svc_uuid, PUBLIC_BROWSE_GROUP);
+               search_list = sdp_list_append(NULL, &svc_uuid);
+
+               range = 0x0000ffff;
+               attrid_list = sdp_list_append(NULL, &range);
+
+               err = sdp_service_search_attr_req(session, search_list,
+                                                 SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
+
+               if (err >= 0) {
+                       for (r = response_list; r; r = r->next) {
+                               sdp_record_t *rec = (sdp_record_t*) r->data;
+                               sdp_list_t *proto_list;
+                               sdp_list_t *access = NULL;
+                               int proto;
+
+                               proto = sdp_uuid_to_proto(&rec->svclass);
+
+                               if (proto == SERIAL_PORT_SVCLASS_ID) {
+                                       sdp_get_access_protos(rec, &access);
+                                       if (access) {
+                                               int this_chan = sdp_get_proto_port(access, RFCOMM_UUID);
+                                               if (this_chan)
+                                                       channel = this_chan;
+                                       }
+                               }
+                       }
+               }
+
+               /* Leave the session open so we don't disconnect from the device before opening
+                * the RFCOMM channel
+                */
+       }
+#endif
+       if (channel == 0)
+               channel = altos_bt_port(device);
+
+       /* Connect to the channel */
        file = calloc(1, sizeof (struct altos_file_posix));
        if (!file) {
                errno = ENOMEM;
@@ -485,11 +573,7 @@ altos_bt_open(struct altos_bt_device *device)
                goto no_file;
        }
        addr.rc_family = AF_BLUETOOTH;
-       addr.rc_channel = 1;
-       if (str2ba(device->addr, &addr.rc_bdaddr) < 0) {
-               altos_set_last_posix_error();
-               goto no_sock;
-       }
+       addr.rc_channel = channel;
 
        for (i = 0; i < 5; i++) {
                file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
@@ -506,10 +590,16 @@ altos_bt_open(struct altos_bt_device *device)
                close(file->fd);
                usleep(100 * 1000);
        }
+
+
        if (status < 0) {
                altos_set_last_posix_error();
                goto no_link;
        }
+
+       if (session)
+               sdp_close(session);
+
        usleep(100 * 1000);
 
 #ifdef USE_POLL
@@ -517,12 +607,14 @@ altos_bt_open(struct altos_bt_device *device)
 #else
        file->out_fd = dup(file->fd);
 #endif
-       return file;
+       return &file->file;
 no_link:
        close(file->fd);
 no_sock:
        free(file);
 no_file:
+       if (session)
+               sdp_close(session);
        return NULL;
 }