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