process updates made during 1.6.3 release cycle
[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 <IOKit/serial/IOSerialKeys.h>
24 #include <usb/IOUSBLib.h>
25 #include <usb/USBSpec.h>
26 #include <sys/param.h>
27 #include <paths.h>
28 #include <CFNumber.h>
29 #include <IOBSD.h>
30
31 /* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
32 char *
33 altos_strndup (const char *s, size_t n)
34 {
35     size_t len = strlen (s);
36     char *ret;
37
38     if (len <= n)
39        return strdup (s);
40     ret = malloc(n + 1);
41     strncpy(ret, s, n);
42     ret[n] = '\0';
43     return ret;
44 }
45
46 struct altos_list {
47         io_iterator_t iterator;
48         int ftdi;
49 };
50
51 static char *
52 get_cfstring(CFTypeRef string, char result[512])
53 {
54         Boolean         got_string;
55
56         got_string = CFStringGetCString(string, result, 512, kCFStringEncodingASCII);
57         if (!got_string)
58                 strcpy(result, "CFStringGetCString failed");
59         return result;
60 }
61
62 static int
63 get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
64 {
65         CFTypeRef entry_as_string;
66         Boolean got_string;
67         char entry_string[512];
68
69         entry_as_string = IORegistryEntrySearchCFProperty (object,
70                                                            kIOServicePlane,
71                                                            entry,
72                                                            kCFAllocatorDefault,
73                                                            kIORegistryIterateRecursively);
74         if (entry_as_string) {
75                 got_string = CFStringGetCString(entry_as_string,
76                                                 result, result_len,
77                                                 kCFStringEncodingASCII);
78
79                 CFRelease(entry_as_string);
80                 if (got_string) {
81                         return 1;
82                 }
83         }
84         return 0;
85 }
86
87 static int
88 get_number(io_object_t object, CFStringRef entry, int *result)
89 {
90         CFTypeRef entry_as_number;
91         Boolean got_number;
92         char entry_string[512];
93
94         entry_as_number = IORegistryEntrySearchCFProperty (object,
95                                                            kIOServicePlane,
96                                                            entry,
97                                                            kCFAllocatorDefault,
98                                                            kIORegistryIterateRecursively);
99         if (entry_as_number) {
100                 got_number = CFNumberGetValue(entry_as_number,
101                                               kCFNumberIntType,
102                                               result);
103                 if (got_number) {
104                         return 1;
105                 }
106         }
107         return 0;
108 }
109
110 PUBLIC struct altos_list *
111 altos_list_start(void)
112 {
113         struct altos_list *list = calloc (sizeof (struct altos_list), 1);
114         CFMutableDictionaryRef matching_dictionary;
115         io_iterator_t tdIterator;
116         io_object_t tdObject;
117         kern_return_t ret;
118         int i;
119
120         matching_dictionary = IOServiceMatching(kIOSerialBSDServiceValue);
121         if (matching_dictionary) {
122                 CFDictionarySetValue(matching_dictionary,
123                                      CFSTR(kIOSerialBSDTypeKey),
124                                      CFSTR(kIOSerialBSDAllTypes));
125         }
126
127         ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
128         if (ret != kIOReturnSuccess) {
129                 free(list);
130                 return NULL;
131         }
132         list->ftdi = 0;
133         return list;
134 }
135
136 PUBLIC struct altos_list *
137 altos_ftdi_list_start(void)
138 {
139         struct altos_list *list = altos_list_start();
140
141         if (list)
142                 list->ftdi = 1;
143         return list;
144 }
145
146 static io_service_t get_usb_object(io_object_t serial_device)
147 {
148         io_iterator_t iterator;
149         io_service_t usb_device;
150         io_service_t service;
151         IOReturn status;
152
153         status = IORegistryEntryCreateIterator(serial_device,
154                                       kIOServicePlane,
155                                       kIORegistryIterateParents | kIORegistryIterateRecursively,
156                                       &iterator);
157
158         if (status != kIOReturnSuccess)
159                 return 0;
160
161         while((service = IOIteratorNext(iterator))) {
162                 io_name_t servicename;
163                 status = IORegistryEntryGetNameInPlane(service, kIOServicePlane, servicename);
164
165                 if (status == kIOReturnSuccess && IOObjectConformsTo(service, kIOUSBDeviceClassName)) {
166                         IOObjectRelease(iterator);
167                         return service;
168                 }
169                 IOObjectRelease(service);
170         }
171         IOObjectRelease(iterator);
172         return 0;
173 }
174
175 PUBLIC int
176 altos_list_next(struct altos_list *list, struct altos_device *device)
177 {
178
179         io_object_t object;
180         io_service_t usb_device;
181         char serial_string[128];
182
183         for (;;) {
184                 object = IOIteratorNext(list->iterator);
185                 if (!object) {
186                         return 0;
187                 }
188
189                 usb_device = get_usb_object(object);
190
191                 if (get_number (usb_device, CFSTR(kUSBVendorID), &device->vendor) &&
192                     get_number (usb_device, CFSTR(kUSBProductID), &device->product) &&
193                     get_string (object, CFSTR(kIOCalloutDeviceKey), device->path, sizeof (device->path)) &&
194                     get_string (usb_device, CFSTR(kUSBProductString), device->name, sizeof (device->name)) &&
195                     get_string (usb_device, CFSTR(kUSBSerialNumberString), serial_string, sizeof (serial_string))) {
196                         device->serial = atoi(serial_string);
197                         IOObjectRelease(object);
198                         IOObjectRelease(usb_device);
199                         return 1;
200                 }
201                 IOObjectRelease(object);
202                 IOObjectRelease(usb_device);
203         }
204 }
205
206 PUBLIC void
207 altos_list_finish(struct altos_list *list)
208 {
209         IOObjectRelease (list->iterator);
210         free(list);
211 }
212
213 struct altos_bt_list {
214         int             sock;
215         int             dev_id;
216         int             rsp;
217         int             num_rsp;
218 };
219
220 #define INQUIRY_MAX_RSP 255
221
222 struct altos_bt_list *
223 altos_bt_list_start(int inquiry_time)
224 {
225         return NULL;
226 }
227
228 int
229 altos_bt_list_next(struct altos_bt_list *bt_list,
230                    struct altos_bt_device *device)
231 {
232         return 0;
233 }
234
235 void
236 altos_bt_list_finish(struct altos_bt_list *bt_list)
237 {
238 }
239
240 void
241 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
242 {
243         strncpy(device->name, name, sizeof (device->name));
244         device->name[sizeof(device->name)-1] = '\0';
245         strncpy(device->addr, addr, sizeof (device->addr));
246         device->addr[sizeof(device->addr)-1] = '\0';
247 }
248
249 struct altos_file *
250 altos_bt_open(struct altos_bt_device *device)
251 {
252         return NULL;
253 }