altosuilib: Wait for product data while scanning
[fw/altos] / libaltos / libaltos.c
index a623d5ae0b5c187f9b0c5a7bec962b1c73e2451d..97b7b3f9bba44037206e409362824131c833bec9 100644 (file)
@@ -643,6 +643,49 @@ altos_list_finish(struct altos_list *usbdevs)
        free(usbdevs);
 }
 
+#include <dlfcn.h>
+
+static void *libbt;
+static int bt_initialized;
+
+static int init_bt(void) {
+       if (!bt_initialized) {
+               bt_initialized = 1;
+               libbt = dlopen("libbluetooth.so.3", RTLD_LAZY);
+               if (!libbt)
+                       printf("failed to find bluetooth library\n");
+       }
+       return libbt != NULL;
+}
+
+#define join(a,b)      a ## b
+#define bt_func(name, ret, fail, formals, actuals)                     \
+       static ret join(altos_, name) formals {                         \
+                                     static ret (*name) formals;       \
+                                     if (!init_bt()) return fail;      \
+                                     name = dlsym(libbt, #name);       \
+                                     if (!name) return fail;           \
+                                     return name actuals;              \
+                                     }
+
+bt_func(ba2str, int, -1, (const bdaddr_t *ba, char *str), (ba, str))
+#define ba2str altos_ba2str
+
+bt_func(str2ba, int, -1, (const char *str, bdaddr_t *ba), (str, ba))
+#define str2ba altos_str2ba
+
+bt_func(hci_read_remote_name, int, -1, (int sock, const bdaddr_t *ba, int len, char *name, int timeout), (sock, ba, len, name, timeout))
+#define hci_read_remote_name altos_hci_read_remote_name
+
+bt_func(hci_open_dev, int, -1, (int dev_id), (dev_id))
+#define hci_open_dev altos_hci_open_dev
+
+bt_func(hci_get_route, int, -1, (bdaddr_t *bdaddr), (bdaddr))
+#define hci_get_route altos_hci_get_route
+
+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
+
 struct altos_bt_list {
        inquiry_info    *ii;
        int             sock;
@@ -706,7 +749,8 @@ altos_bt_list_next(struct altos_bt_list *bt_list,
                return 0;
 
        ii = &bt_list->ii[bt_list->rsp];
-       ba2str(&ii->bdaddr, device->addr);
+       if (ba2str(&ii->bdaddr, device->addr) < 0)
+               return 0;
        memset(&device->name, '\0', sizeof (device->name));
        if (hci_read_remote_name(bt_list->sock, &ii->bdaddr,
                                 sizeof (device->name),
@@ -742,11 +786,17 @@ altos_bt_open(struct altos_bt_device *device)
        struct altos_file *file;
 
        file = calloc(1, sizeof (struct altos_file));
-       if (!file)
+       if (!file) {
+               errno = ENOMEM;
+               altos_set_last_posix_error();
                goto no_file;
+       }
        addr.rc_family = AF_BLUETOOTH;
        addr.rc_channel = 1;
-       str2ba(device->addr, &addr.rc_bdaddr);
+       if (str2ba(device->addr, &addr.rc_bdaddr) < 0) {
+               altos_set_last_posix_error();
+               goto no_sock;
+       }
 
        for (i = 0; i < 5; i++) {
                file->fd = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
@@ -817,7 +867,7 @@ get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
                got_string = CFStringGetCString(entry_as_string,
                                                result, result_len,
                                                kCFStringEncodingASCII);
-    
+
                CFRelease(entry_as_string);
                if (got_string)
                        return 1;
@@ -830,7 +880,7 @@ get_number(io_object_t object, CFStringRef entry, int *result)
 {
        CFTypeRef entry_as_number;
        Boolean got_number;
-       
+
        entry_as_number = IORegistryEntrySearchCFProperty (object,
                                                           kIOServicePlane,
                                                           entry,
@@ -885,7 +935,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
                object = IOIteratorNext(list->iterator);
                if (!object)
                        return 0;
-  
+
                if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
                    !get_number (object, CFSTR(kUSBProductID), &device->product))
                        continue;
@@ -989,7 +1039,7 @@ log_message(char *fmt, ...)
        if (log) {
                SYSTEMTIME time;
                GetLocalTime(&time);
-               fprintf (log, "%4d-%02d-%02d %2d:%02d:%02d. ", 
+               fprintf (log, "%4d-%02d-%02d %2d:%02d:%02d. ",
                         time.wYear, time.wMonth, time.wDay,
                         time.wHour, time.wMinute, time.wSecond);
                va_start(a, fmt);
@@ -1071,6 +1121,8 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
        HRESULT         result;
        DWORD           friendlyname_type;
        DWORD           friendlyname_len;
+       char            instanceid[1024];
+       DWORD           instanceid_len;
 
        dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
        while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
@@ -1091,6 +1143,7 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
                        pid = 0x6015;
                        serial = 0;
                } else {
+                       vid = pid = serial = 0;
                        /* Fetch symbolic name for this device and parse out
                         * the vid/pid/serial info */
                        symbolic_len = sizeof(symbolic);
@@ -1098,16 +1151,34 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
                                                 symbolic, &symbolic_len);
                        if (result != 0) {
                                altos_set_last_windows_error();
+                       } else {
+                               sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1,
+                                      "%04X", &vid);
+                               sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
+                                      "%04X", &pid);
+                               sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
+                                      "%d", &serial);
+                       }
+                       if (vid == 0 || pid == 0 || serial == 0) {
+                               if (SetupDiGetDeviceInstanceId(list->dev_info,
+                                                              &dev_info_data,
+                                                              instanceid,
+                                                              sizeof (instanceid),
+                                                              &instanceid_len)) {
+                                       sscanf((char *) instanceid + sizeof("USB\\VID_") - 1,
+                                              "%04X", &vid);
+                                       sscanf((char *) instanceid + sizeof("USB\\VID_XXXX&PID_") - 1,
+                                              "%04X", &pid);
+                                       sscanf((char *) instanceid + sizeof("USB\\VID_XXXX&PID_XXXX\\") - 1,
+                                              "%d", &serial);
+                               } else {
+                                       altos_set_last_windows_error();
+                               }
+                       }
+                       if (vid == 0 || pid == 0 || serial == 0) {
                                RegCloseKey(dev_key);
                                continue;
                        }
-                       vid = pid = serial = 0;
-                       sscanf((char *) symbolic + sizeof("\\??\\USB#VID_") - 1,
-                              "%04X", &vid);
-                       sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
-                              "%04X", &pid);
-                       sscanf((char *) symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
-                              "%d", &serial);
                }
 
                /* Fetch the com port name */
@@ -1340,7 +1411,7 @@ altos_open(struct altos_device *device)
                altos_set_last_windows_error();
                Sleep(100);
        }
-       
+
        if (file->handle == INVALID_HANDLE_VALUE) {
                free(file);
                return NULL;