altos/test: Adjust CRC error rate after FEC fix
[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; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
17  */
18
19 #include "libaltos_private.h"
20 #include "libaltos_posix.h"
21
22 #include <IOKitLib.h>
23 #include <IOKit/usb/USBspec.h>
24 #include <IOKit/serial/IOSerialKeys.h>
25 #include <usb/IOUSBLib.h>
26 #include <usb/USBSpec.h>
27 #include <sys/param.h>
28 #include <paths.h>
29 #include <CFNumber.h>
30 #include <IOBSD.h>
31
32 /* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
33 char *
34 altos_strndup (const char *s, size_t n)
35 {
36     size_t len = strlen (s);
37     char *ret;
38
39     if (len <= n)
40        return strdup (s);
41     ret = malloc(n + 1);
42     strncpy(ret, s, n);
43     ret[n] = '\0';
44     return ret;
45 }
46
47 struct altos_list {
48         io_iterator_t iterator;
49         int ftdi;
50 };
51
52 static char *
53 get_cfstring(CFTypeRef string, char result[512])
54 {
55         Boolean         got_string;
56
57         got_string = CFStringGetCString(string, result, 512, kCFStringEncodingASCII);
58         if (!got_string)
59                 strcpy(result, "CFStringGetCString failed");
60         return result;
61 }
62
63 static int
64 get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
65 {
66         CFTypeRef entry_as_string;
67         Boolean got_string;
68         char entry_string[512];
69
70         entry_as_string = IORegistryEntrySearchCFProperty (object,
71                                                            kIOServicePlane,
72                                                            entry,
73                                                            kCFAllocatorDefault,
74                                                            kIORegistryIterateRecursively);
75         if (entry_as_string) {
76                 got_string = CFStringGetCString(entry_as_string,
77                                                 result, result_len,
78                                                 kCFStringEncodingASCII);
79
80                 CFRelease(entry_as_string);
81                 if (got_string) {
82                         return 1;
83                 }
84         }
85         return 0;
86 }
87
88 static int
89 get_number(io_object_t object, CFStringRef entry, int *result)
90 {
91         CFTypeRef entry_as_number;
92         Boolean got_number;
93         char entry_string[512];
94
95         entry_as_number = IORegistryEntrySearchCFProperty (object,
96                                                            kIOServicePlane,
97                                                            entry,
98                                                            kCFAllocatorDefault,
99                                                            kIORegistryIterateRecursively);
100         if (entry_as_number) {
101                 got_number = CFNumberGetValue(entry_as_number,
102                                               kCFNumberIntType,
103                                               result);
104                 if (got_number) {
105                         return 1;
106                 }
107         }
108         return 0;
109 }
110
111 PUBLIC struct altos_list *
112 altos_list_start(void)
113 {
114         struct altos_list *list = calloc (sizeof (struct altos_list), 1);
115         CFMutableDictionaryRef matching_dictionary;
116         io_iterator_t tdIterator;
117         io_object_t tdObject;
118         kern_return_t ret;
119         int i;
120
121         matching_dictionary = IOServiceMatching(kIOSerialBSDServiceValue);
122         if (matching_dictionary) {
123                 CFDictionarySetValue(matching_dictionary,
124                                      CFSTR(kIOSerialBSDTypeKey),
125                                      CFSTR(kIOSerialBSDAllTypes));
126         }
127
128         ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
129         if (ret != kIOReturnSuccess) {
130                 free(list);
131                 return NULL;
132         }
133         list->ftdi = 0;
134         return list;
135 }
136
137 PUBLIC struct altos_list *
138 altos_ftdi_list_start(void)
139 {
140         struct altos_list *list = altos_list_start();
141
142         if (list)
143                 list->ftdi = 1;
144         return list;
145 }
146
147 static io_service_t get_usb_object(io_object_t serial_device)
148 {
149         io_iterator_t iterator;
150         io_service_t usb_device;
151         io_service_t service;
152         IOReturn status;
153
154         status = IORegistryEntryCreateIterator(serial_device,
155                                       kIOServicePlane,
156                                       kIORegistryIterateParents | kIORegistryIterateRecursively,
157                                       &iterator);
158
159         if (status != kIOReturnSuccess)
160                 return 0;
161
162         while((service = IOIteratorNext(iterator))) {
163                 io_name_t servicename;
164                 status = IORegistryEntryGetNameInPlane(service, kIOServicePlane, servicename);
165
166                 if (status == kIOReturnSuccess && IOObjectConformsTo(service, kIOUSBDeviceClassName)) {
167                         IOObjectRelease(iterator);
168                         return service;
169                 }
170                 IOObjectRelease(service);
171         }
172         IOObjectRelease(iterator);
173         return 0;
174 }
175
176 PUBLIC int
177 altos_list_next(struct altos_list *list, struct altos_device *device)
178 {
179
180         io_object_t object;
181         io_service_t usb_device;
182         char serial_string[128];
183
184         for (;;) {
185                 object = IOIteratorNext(list->iterator);
186                 if (!object) {
187                         return 0;
188                 }
189
190                 usb_device = get_usb_object(object);
191
192                 if (get_number (usb_device, CFSTR(kUSBVendorID), &device->vendor) &&
193                     get_number (usb_device, CFSTR(kUSBProductID), &device->product) &&
194                     get_string (object, CFSTR(kIOCalloutDeviceKey), device->path, sizeof (device->path)) &&
195                     get_string (usb_device, CFSTR(kUSBProductString), device->name, sizeof (device->name)) &&
196                     get_string (usb_device, CFSTR(kUSBSerialNumberString), serial_string, sizeof (serial_string))) {
197                         device->serial = atoi(serial_string);
198                         IOObjectRelease(object);
199                         IOObjectRelease(usb_device);
200                         return 1;
201                 }
202                 IOObjectRelease(object);
203                 IOObjectRelease(usb_device);
204         }
205 }
206
207 PUBLIC void
208 altos_list_finish(struct altos_list *list)
209 {
210         IOObjectRelease (list->iterator);
211         free(list);
212 }
213
214 struct altos_bt_list {
215         int             sock;
216         int             dev_id;
217         int             rsp;
218         int             num_rsp;
219 };
220
221 #define INQUIRY_MAX_RSP 255
222
223 struct altos_bt_list *
224 altos_bt_list_start(int inquiry_time)
225 {
226         return NULL;
227 }
228
229 int
230 altos_bt_list_next(struct altos_bt_list *bt_list,
231                    struct altos_bt_device *device)
232 {
233         return 0;
234 }
235
236 void
237 altos_bt_list_finish(struct altos_bt_list *bt_list)
238 {
239 }
240
241 void
242 altos_bt_fill_in(char *name, char *addr, struct altos_bt_device *device)
243 {
244         strncpy(device->name, name, sizeof (device->name));
245         device->name[sizeof(device->name)-1] = '\0';
246         strncpy(device->addr, addr, sizeof (device->addr));
247         device->addr[sizeof(device->addr)-1] = '\0';
248 }
249
250 struct altos_file *
251 altos_bt_open(struct altos_bt_device *device)
252 {
253         return NULL;
254 }