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