]> sigrok.org Git - libserialport.git/blob - macosx.c
Check bus:address and vid:pid validity.
[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 enum sp_return get_port_details(struct sp_port *port)
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];
31         char baddr[32];
32         CFMutableDictionaryRef classes;
33         io_iterator_t iter;
34         io_object_t ioport;
35         CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product;
36         Boolean result;
37         char path[PATH_MAX];
38
39         DEBUG("Getting serial port list");
40         if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
41                 RETURN_FAIL("IOServiceMatching() failed");
42
43         if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
44                                          &iter) != KERN_SUCCESS)
45                 RETURN_FAIL("IOServiceGetMatchingServices() failed");
46
47         DEBUG("Iterating over results");
48         while ((ioport = IOIteratorNext(iter))) {
49                 if (!(cf_property = IORegistryEntryCreateCFProperty(ioport,
50                             CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) {
51                         IOObjectRelease(ioport);
52                         continue;
53                 }
54                 result = CFStringGetCString(cf_property, path, sizeof(path),
55                                             kCFStringEncodingASCII);
56                 CFRelease(cf_property);
57                 if (!result || strcmp(path, port->name)) {
58                         IOObjectRelease(ioport);
59                         continue;
60                 }
61                 DEBUG("Found port %s", path);
62
63                 IORegistryEntryGetParentEntry(ioport, kIOServicePlane, &ioparent);
64                 if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane,
65                            CFSTR("IOProviderClass"), kCFAllocatorDefault,
66                            kIORegistryIterateRecursively | kIORegistryIterateParents))) {
67                         if (CFStringGetCString(cf_property, class, sizeof(class),
68                                                kCFStringEncodingASCII) &&
69                             strstr(class, "USB")) {
70                                 DEBUG("Found USB class device");
71                                 port->transport = SP_TRANSPORT_USB;
72                         }
73                         CFRelease(cf_property);
74                 }
75                 IOObjectRelease(ioparent);
76
77                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
78                          CFSTR("USB Interface Name"), kCFAllocatorDefault,
79                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
80                     (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
81                          CFSTR("USB Product Name"), kCFAllocatorDefault,
82                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
83                     (cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
84                          CFSTR("Product Name"), kCFAllocatorDefault,
85                          kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
86                     (cf_property = IORegistryEntryCreateCFProperty(ioport,
87                          CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) {
88                         if (CFStringGetCString(cf_property, description, sizeof(description),
89                                                kCFStringEncodingASCII)) {
90                                 DEBUG("Found description %s", description);
91                                 port->description = strdup(description);
92                         }
93                         CFRelease(cf_property);
94                 } else {
95                         DEBUG("No description for this device");
96                 }
97
98                 cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
99                                                          CFSTR("USBBusNumber"),
100                                                          kCFAllocatorDefault,
101                                                          kIORegistryIterateRecursively
102                                                          | kIORegistryIterateParents);
103                 cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
104                                                          CFSTR("USB Address"),
105                                                          kCFAllocatorDefault,
106                                                          kIORegistryIterateRecursively
107                                                          | kIORegistryIterateParents);
108                 if (cf_bus && cf_address &&
109                     CFNumberGetValue(cf_bus    , kCFNumberIntType, &bus) &&
110                     CFNumberGetValue(cf_address, kCFNumberIntType, &address)) {
111                         DEBUG("Found matching USB bus:address %03d:%03d", bus, address);
112                         port->usb_bus = bus;
113                         port->usb_address = address;
114                 }
115                 if (cf_bus    )  CFRelease(cf_bus);
116                 if (cf_address)  CFRelease(cf_address);
117
118                 cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
119                                                          CFSTR("idVendor"),
120                                                          kCFAllocatorDefault,
121                                                          kIORegistryIterateRecursively
122                                                          | kIORegistryIterateParents);
123                 cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
124                                                          CFSTR("idProduct"),
125                                                          kCFAllocatorDefault,
126                                                          kIORegistryIterateRecursively
127                                                          | kIORegistryIterateParents);
128                 if (cf_vendor && cf_product &&
129                     CFNumberGetValue(cf_vendor , kCFNumberIntType, &vid) &&
130                     CFNumberGetValue(cf_product, kCFNumberIntType, &pid)) {
131                         DEBUG("Found matching USB vid:pid %04X:%04X", vid, pid);
132                         port->usb_vid = vid;
133                         port->usb_pid = pid;
134                 }
135                 if (cf_vendor )  CFRelease(cf_vendor);
136                 if (cf_product)  CFRelease(cf_product);
137
138                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
139                          CFSTR("USB Vendor Name"), kCFAllocatorDefault,
140                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
141                         if (CFStringGetCString(cf_property, manufacturer, sizeof(manufacturer),
142                                                kCFStringEncodingASCII)) {
143                                 DEBUG("Found manufacturer %s", manufacturer);
144                                 port->usb_manufacturer = strdup(manufacturer);
145                         }
146                         CFRelease(cf_property);
147                 }
148
149                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
150                          CFSTR("USB Product Name"), kCFAllocatorDefault,
151                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
152                         if (CFStringGetCString(cf_property, product, sizeof(product),
153                                                kCFStringEncodingASCII)) {
154                                 DEBUG("Found product name %s", product);
155                                 port->usb_product = strdup(product);
156                         }
157                         CFRelease(cf_property);
158                 }
159
160                 if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
161                          CFSTR("USB Serial Number"), kCFAllocatorDefault,
162                          kIORegistryIterateRecursively | kIORegistryIterateParents))) {
163                         if (CFStringGetCString(cf_property, serial, sizeof(serial),
164                                                kCFStringEncodingASCII)) {
165                                 DEBUG("Found serial number %s", serial);
166                                 port->usb_serial = strdup(serial);
167                         }
168                         CFRelease(cf_property);
169                 }
170
171                 IOObjectRelease(ioport);
172                 break;
173         }
174         IOObjectRelease(iter);
175
176         RETURN_OK();
177 }