]> sigrok.org Git - libserialport.git/blob - macosx.c
change type of result variables to ssize_t
[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 <config.h>
22 #include "libserialport.h"
23 #include "libserialport_internal.h"
24
25 SP_PRIV enum sp_return get_port_details(struct sp_port *port)
26 {
27         /*
28          * Description limited to 127 char, anything longer
29          * would not be user friendly anyway.
30          */
31         char description[128];
32         int bus, address, vid, pid = -1;
33         char manufacturer[128], product[128], serial[128];
34         CFMutableDictionaryRef classes;
35         io_iterator_t iter;
36         io_object_t ioport, ioparent;
37         CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product;
38         Boolean result;
39         char path[PATH_MAX], class[16];
40
41         DEBUG("Getting serial port list");
42         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
43                 RETURN_FAIL("IOServiceMatching() failed");
44
45         if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
46                                          &iter) != KERN_SUCCESS)
47                 RETURN_FAIL("IOServiceGetMatchingServices() failed");
48
49         DEBUG("Iterating over results");
50         while ((ioport = IOIteratorNext(iter))) {
51                 if (!(cf_property = IORegistryEntryCreateCFProperty(ioport,
52                             CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) {
53                         IOObjectRelease(ioport);
54                         continue;
55                 }
56                 result = CFStringGetCString(cf_property, path, sizeof(path),
57                                             kCFStringEncodingASCII);
58                 CFRelease(cf_property);
59                 if (!result || strcmp(path, port->name)) {
60                         IOObjectRelease(ioport);
61                         continue;
62                 }
63                 DEBUG_FMT("Found port %s", path);
64
65                 IORegistryEntryGetParentEntry(ioport, kIOServicePlane, &ioparent);
66                 if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane,
67                            CFSTR("IOClass"), kCFAllocatorDefault,
68                            kIORegistryIterateRecursively | kIORegistryIterateParents))) {
69                         if (CFStringGetCString(cf_property, class, sizeof(class),
70                                                kCFStringEncodingASCII) &&
71                             strstr(class, "USB")) {
72                                 DEBUG("Found USB class device");
73                                 port->transport = SP_TRANSPORT_USB;
74                         }
75                         CFRelease(cf_property);
76                 }
77                 if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane,
78                            CFSTR("IOProviderClass"), kCFAllocatorDefault,
79                            kIORegistryIterateRecursively | kIORegistryIterateParents))) {
80                         if (CFStringGetCString(cf_property, class, sizeof(class),
81                                                kCFStringEncodingASCII) &&
82                             strstr(class, "USB")) {
83                                 DEBUG("Found USB class device");
84                                 port->transport = SP_TRANSPORT_USB;
85                         }
86                         CFRelease(cf_property);
87                 }
88                 IOObjectRelease(ioparent);
89
90                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
91                          CFSTR("USB Interface Name"), kCFAllocatorDefault,
92                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
93                     (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
94                          CFSTR("USB Product Name"), kCFAllocatorDefault,
95                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
96                     (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
97                          CFSTR("Product Name"), kCFAllocatorDefault,
98                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
99                     (cf_property = IORegistryEntryCreateCFProperty(ioport,
100                          CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) {
101                         if (CFStringGetCString(cf_property, description, sizeof(description),
102                                                kCFStringEncodingASCII)) {
103                                 DEBUG_FMT("Found description %s", description);
104                                 port->description = strdup(description);
105                         }
106                         CFRelease(cf_property);
107                 } else {
108                         DEBUG("No description for this device");
109                 }
110
111                 cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
112                                                          CFSTR("USBBusNumber"),
113                                                          kCFAllocatorDefault,
114                                                          kIORegistryIterateRecursively
115                                                          | kIORegistryIterateParents);
116                 cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
117                                                          CFSTR("USB Address"),
118                                                          kCFAllocatorDefault,
119                                                          kIORegistryIterateRecursively
120                                                          | kIORegistryIterateParents);
121                 if (cf_bus && cf_address &&
122                     CFNumberGetValue(cf_bus    , kCFNumberIntType, &bus) &&
123                     CFNumberGetValue(cf_address, kCFNumberIntType, &address)) {
124                         DEBUG_FMT("Found matching USB bus:address %03d:%03d", bus, address);
125                         port->usb_bus = bus;
126                         port->usb_address = address;
127                 }
128                 if (cf_bus)
129                         CFRelease(cf_bus);
130                 if (cf_address)
131                         CFRelease(cf_address);
132
133                 cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
134                                                          CFSTR("idVendor"),
135                                                          kCFAllocatorDefault,
136                                                          kIORegistryIterateRecursively
137                                                          | kIORegistryIterateParents);
138                 cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
139                                                          CFSTR("idProduct"),
140                                                          kCFAllocatorDefault,
141                                                          kIORegistryIterateRecursively
142                                                          | kIORegistryIterateParents);
143                 if (cf_vendor && cf_product &&
144                     CFNumberGetValue(cf_vendor , kCFNumberIntType, &vid) &&
145                     CFNumberGetValue(cf_product, kCFNumberIntType, &pid)) {
146                         DEBUG_FMT("Found matching USB VID:PID %04X:%04X", vid, pid);
147                         port->usb_vid = vid;
148                         port->usb_pid = pid;
149                 }
150                 if (cf_vendor)
151                         CFRelease(cf_vendor);
152                 if (cf_product)
153                         CFRelease(cf_product);
154
155                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
156                          CFSTR("USB Vendor Name"), kCFAllocatorDefault,
157                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
158                         if (CFStringGetCString(cf_property, manufacturer, sizeof(manufacturer),
159                                                kCFStringEncodingASCII)) {
160                                 DEBUG_FMT("Found manufacturer %s", manufacturer);
161                                 port->usb_manufacturer = strdup(manufacturer);
162                         }
163                         CFRelease(cf_property);
164                 }
165
166                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
167                          CFSTR("USB Product Name"), kCFAllocatorDefault,
168                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
169                         if (CFStringGetCString(cf_property, product, sizeof(product),
170                                                kCFStringEncodingASCII)) {
171                                 DEBUG_FMT("Found product name %s", product);
172                                 port->usb_product = strdup(product);
173                         }
174                         CFRelease(cf_property);
175                 }
176
177                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
178                          CFSTR("USB Serial Number"), kCFAllocatorDefault,
179                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
180                         if (CFStringGetCString(cf_property, serial, sizeof(serial),
181                                                kCFStringEncodingASCII)) {
182                                 DEBUG_FMT("Found serial number %s", serial);
183                                 port->usb_serial = strdup(serial);
184                         }
185                         CFRelease(cf_property);
186                 }
187
188                 IOObjectRelease(ioport);
189                 break;
190         }
191         IOObjectRelease(iter);
192
193         RETURN_OK();
194 }
195
196 SP_PRIV enum sp_return list_ports(struct sp_port ***list)
197 {
198         CFMutableDictionaryRef classes;
199         io_iterator_t iter;
200         char path[PATH_MAX];
201         io_object_t port;
202         CFTypeRef cf_path;
203         Boolean result;
204         int ret = SP_OK;
205
206         DEBUG("Creating matching dictionary");
207         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
208                 SET_FAIL(ret, "IOServiceMatching() failed");
209                 goto out_done;
210         }
211
212         DEBUG("Getting matching services");
213         if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
214                                          &iter) != KERN_SUCCESS) {
215                 SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
216                 goto out_done;
217         }
218
219         DEBUG("Iterating over results");
220         while ((port = IOIteratorNext(iter))) {
221                 cf_path = IORegistryEntryCreateCFProperty(port,
222                                 CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
223                 if (cf_path) {
224                         result = CFStringGetCString(cf_path, path, sizeof(path),
225                                                     kCFStringEncodingASCII);
226                         CFRelease(cf_path);
227                         if (result) {
228                                 DEBUG_FMT("Found port %s", path);
229                                 if (!(*list = list_append(*list, path))) {
230                                         SET_ERROR(ret, SP_ERR_MEM, "List append failed");
231                                         IOObjectRelease(port);
232                                         goto out;
233                                 }
234                         }
235                 }
236                 IOObjectRelease(port);
237         }
238 out:
239         IOObjectRelease(iter);
240 out_done:
241
242         return ret;
243 }