libaltos: Add Windows BT support. Split into separate source files.
[fw/altos] / libaltos / libaltos_darwin.c
1 /*
2  * Copyright © 2016 Keith Packard <keithp@keithp.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
16  */
17
18 #include "libaltos_private.h"
19 #include "libaltos_posix.h"
20
21 #include <IOKitLib.h>
22 #include <IOKit/usb/USBspec.h>
23 #include <sys/param.h>
24 #include <paths.h>
25 #include <CFNumber.h>
26 #include <IOBSD.h>
27
28 /* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
29 char *
30 altos_strndup (const char *s, size_t n)
31 {
32     size_t len = strlen (s);
33     char *ret;
34
35     if (len <= n)
36        return strdup (s);
37     ret = malloc(n + 1);
38     strncpy(ret, s, n);
39     ret[n] = '\0';
40     return ret;
41 }
42
43 struct altos_list {
44         io_iterator_t iterator;
45         int ftdi;
46 };
47
48 static int
49 get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
50 {
51         CFTypeRef entry_as_string;
52         Boolean got_string;
53
54         entry_as_string = IORegistryEntrySearchCFProperty (object,
55                                                            kIOServicePlane,
56                                                            entry,
57                                                            kCFAllocatorDefault,
58                                                            kIORegistryIterateRecursively);
59         if (entry_as_string) {
60                 got_string = CFStringGetCString(entry_as_string,
61                                                 result, result_len,
62                                                 kCFStringEncodingASCII);
63
64                 CFRelease(entry_as_string);
65                 if (got_string)
66                         return 1;
67         }
68         return 0;
69 }
70
71 static int
72 get_number(io_object_t object, CFStringRef entry, int *result)
73 {
74         CFTypeRef entry_as_number;
75         Boolean got_number;
76
77         entry_as_number = IORegistryEntrySearchCFProperty (object,
78                                                            kIOServicePlane,
79                                                            entry,
80                                                            kCFAllocatorDefault,
81                                                            kIORegistryIterateRecursively);
82         if (entry_as_number) {
83                 got_number = CFNumberGetValue(entry_as_number,
84                                               kCFNumberIntType,
85                                               result);
86                 if (got_number)
87                         return 1;
88         }
89         return 0;
90 }
91
92 PUBLIC struct altos_list *
93 altos_list_start(void)
94 {
95         struct altos_list *list = calloc (sizeof (struct altos_list), 1);
96         CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
97         io_iterator_t tdIterator;
98         io_object_t tdObject;
99         kern_return_t ret;
100         int i;
101
102         ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
103         if (ret != kIOReturnSuccess) {
104                 free(list);
105                 return NULL;
106         }
107         list->ftdi = 0;
108         return list;
109 }
110
111 PUBLIC struct altos_list *
112 altos_ftdi_list_start(void)
113 {
114         struct altos_list *list = altos_list_start();
115
116         if (list)
117                 list->ftdi = 1;
118         return list;
119 }
120
121 PUBLIC int
122 altos_list_next(struct altos_list *list, struct altos_device *device)
123 {
124         io_object_t object;
125         char serial_string[128];
126
127         for (;;) {
128                 object = IOIteratorNext(list->iterator);
129                 if (!object)
130                         return 0;
131
132                 if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
133                     !get_number (object, CFSTR(kUSBProductID), &device->product))
134                         continue;
135                 if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
136                     get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
137                     get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
138                         device->serial = atoi(serial_string);
139                         return 1;
140                 }
141         }
142 }
143
144 PUBLIC void
145 altos_list_finish(struct altos_list *list)
146 {
147         IOObjectRelease (list->iterator);
148         free(list);
149 }
150
151 struct altos_bt_list {
152         int             sock;
153         int             dev_id;
154         int             rsp;
155         int             num_rsp;
156 };
157
158 #define INQUIRY_MAX_RSP 255
159
160 struct altos_bt_list *
161 altos_bt_list_start(int inquiry_time)
162 {
163         return NULL;
164 }
165
166 int
167 altos_bt_list_next(struct altos_bt_list *bt_list,
168                    struct altos_bt_device *device)
169 {
170         return 0;
171 }
172
173 void
174 altos_bt_list_finish(struct altos_bt_list *bt_list)
175 {
176 }
177
178 void
179 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
180 {
181         strncpy(device->name, name, sizeof (device->name));
182         device->name[sizeof(device->name)-1] = '\0';
183         strncpy(device->addr, addr, sizeof (device->addr));
184         device->addr[sizeof(device->addr)-1] = '\0';
185 }
186
187 struct altos_file *
188 altos_bt_open(struct altos_bt_device *device)
189 {
190         return NULL;
191 }