]> sigrok.org Git - libserialport.git/blob - macosx.c
Build: Use GNUMAKEFLAGS and $@
[libserialport.git] / macosx.c
1 /*
2  * This file is part of the libserialport project.
3  *
4  * Copyright (C) 2013-2014 Martin Ling <martin-libserialport@earth.li>
5  * Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as
9  * published by the Free Software Foundation, either version 3 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "libserialport.h"
22 #include "libserialport_internal.h"
23
24 SP_PRIV enum sp_return get_port_details(struct sp_port *port)
25 {
26         /*
27          * Description limited to 127 char, anything longer
28          * would not be user friendly anyway.
29          */
30         char description[128];
31         int bus, address, vid, pid = -1;
32         char manufacturer[128], product[128], serial[128];
33         CFMutableDictionaryRef classes;
34         io_iterator_t iter;
35         io_object_t ioport, ioparent;
36         CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product;
37         Boolean result;
38         char path[PATH_MAX], class[16];
39
40         DEBUG("Getting serial port list");
41         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
42                 RETURN_FAIL("IOServiceMatching() failed");
43
44         if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
45                                          &iter) != KERN_SUCCESS)
46                 RETURN_FAIL("IOServiceGetMatchingServices() failed");
47
48         DEBUG("Iterating over results");
49         while ((ioport = IOIteratorNext(iter))) {
50                 if (!(cf_property = IORegistryEntryCreateCFProperty(ioport,
51                             CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) {
52                         IOObjectRelease(ioport);
53                         continue;
54                 }
55                 result = CFStringGetCString(cf_property, path, sizeof(path),
56                                             kCFStringEncodingASCII);
57                 CFRelease(cf_property);
58                 if (!result || strcmp(path, port->name)) {
59                         IOObjectRelease(ioport);
60                         continue;
61                 }
62                 DEBUG_FMT("Found port %s", path);
63
64                 IORegistryEntryGetParentEntry(ioport, kIOServicePlane, &ioparent);
65                 if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane,
66                            CFSTR("IOProviderClass"), kCFAllocatorDefault,
67                            kIORegistryIterateRecursively | kIORegistryIterateParents))) {
68                         if (CFStringGetCString(cf_property, class, sizeof(class),
69                                                kCFStringEncodingASCII) &&
70                             strstr(class, "USB")) {
71                                 DEBUG("Found USB class device");
72                                 port->transport = SP_TRANSPORT_USB;
73                         }
74                         CFRelease(cf_property);
75                 }
76                 IOObjectRelease(ioparent);
77
78                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
79                          CFSTR("USB Interface Name"), kCFAllocatorDefault,
80                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
81                     (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
82                          CFSTR("USB Product Name"), kCFAllocatorDefault,
83                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
84                     (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
85                          CFSTR("Product Name"), kCFAllocatorDefault,
86                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
87                     (cf_property = IORegistryEntryCreateCFProperty(ioport,
88                          CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) {
89                         if (CFStringGetCString(cf_property, description, sizeof(description),
90                                                kCFStringEncodingASCII)) {
91                                 DEBUG_FMT("Found description %s", description);
92                                 port->description = strdup(description);
93                         }
94                         CFRelease(cf_property);
95                 } else {
96                         DEBUG("No description for this device");
97                 }
98
99                 cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
100                                                          CFSTR("USBBusNumber"),
101                                                          kCFAllocatorDefault,
102                                                          kIORegistryIterateRecursively
103                                                          | kIORegistryIterateParents);
104                 cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
105                                                          CFSTR("USB Address"),
106                                                          kCFAllocatorDefault,
107                                                          kIORegistryIterateRecursively
108                                                          | kIORegistryIterateParents);
109                 if (cf_bus && cf_address &&
110                     CFNumberGetValue(cf_bus    , kCFNumberIntType, &bus) &&
111                     CFNumberGetValue(cf_address, kCFNumberIntType, &address)) {
112                         DEBUG_FMT("Found matching USB bus:address %03d:%03d", bus, address);
113                         port->usb_bus = bus;
114                         port->usb_address = address;
115                 }
116                 if (cf_bus)
117                         CFRelease(cf_bus);
118                 if (cf_address)
119                         CFRelease(cf_address);
120
121                 cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
122                                                          CFSTR("idVendor"),
123                                                          kCFAllocatorDefault,
124                                                          kIORegistryIterateRecursively
125                                                          | kIORegistryIterateParents);
126                 cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
127                                                          CFSTR("idProduct"),
128                                                          kCFAllocatorDefault,
129                                                          kIORegistryIterateRecursively
130                                                          | kIORegistryIterateParents);
131                 if (cf_vendor && cf_product &&
132                     CFNumberGetValue(cf_vendor , kCFNumberIntType, &vid) &&
133                     CFNumberGetValue(cf_product, kCFNumberIntType, &pid)) {
134                         DEBUG_FMT("Found matching USB VID:PID %04X:%04X", vid, pid);
135                         port->usb_vid = vid;
136                         port->usb_pid = pid;
137                 }
138                 if (cf_vendor)
139                         CFRelease(cf_vendor);
140                 if (cf_product)
141                         CFRelease(cf_product);
142
143                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
144                          CFSTR("USB Vendor Name"), kCFAllocatorDefault,
145                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
146                         if (CFStringGetCString(cf_property, manufacturer, sizeof(manufacturer),
147                                                kCFStringEncodingASCII)) {
148                                 DEBUG_FMT("Found manufacturer %s", manufacturer);
149                                 port->usb_manufacturer = strdup(manufacturer);
150                         }
151                         CFRelease(cf_property);
152                 }
153
154                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
155                          CFSTR("USB Product Name"), kCFAllocatorDefault,
156                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
157                         if (CFStringGetCString(cf_property, product, sizeof(product),
158                                                kCFStringEncodingASCII)) {
159                                 DEBUG_FMT("Found product name %s", product);
160                                 port->usb_product = strdup(product);
161                         }
162                         CFRelease(cf_property);
163                 }
164
165                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
166                          CFSTR("USB Serial Number"), kCFAllocatorDefault,
167                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
168                         if (CFStringGetCString(cf_property, serial, sizeof(serial),
169                                                kCFStringEncodingASCII)) {
170                                 DEBUG_FMT("Found serial number %s", serial);
171                                 port->usb_serial = strdup(serial);
172                         }
173                         CFRelease(cf_property);
174                 }
175
176                 IOObjectRelease(ioport);
177                 break;
178         }
179         IOObjectRelease(iter);
180
181         RETURN_OK();
182 }
183
184 SP_PRIV enum sp_return list_ports(struct sp_port ***list)
185 {
186         CFMutableDictionaryRef classes;
187         io_iterator_t iter;
188         char path[PATH_MAX];
189         io_object_t port;
190         CFTypeRef cf_path;
191         Boolean result;
192         int ret = SP_OK;
193
194         DEBUG("Creating matching dictionary");
195         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
196                 SET_FAIL(ret, "IOServiceMatching() failed");
197                 goto out_done;
198         }
199
200         DEBUG("Getting matching services");
201         if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
202                                          &iter) != KERN_SUCCESS) {
203                 SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
204                 goto out_done;
205         }
206
207         DEBUG("Iterating over results");
208         while ((port = IOIteratorNext(iter))) {
209                 cf_path = IORegistryEntryCreateCFProperty(port,
210                                 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
211                 if (cf_path) {
212                         result = CFStringGetCString(cf_path, path, sizeof(path),
213                                                     kCFStringEncodingASCII);
214                         CFRelease(cf_path);
215                         if (result) {
216                                 DEBUG_FMT("Found port %s", path);
217                                 if (!(*list = list_append(*list, path))) {
218                                         SET_ERROR(ret, SP_ERR_MEM, "List append failed");
219                                         IOObjectRelease(port);
220                                         goto out;
221                                 }
222                         }
223                 }
224                 IOObjectRelease(port);
225         }
226 out:
227         IOObjectRelease(iter);
228 out_done:
229
230         return ret;
231 }