]> sigrok.org Git - libserialport.git/blob - windows.c
windows.c: Define a bunch of stuff that's not in MinGW, yet.
[libserialport.git] / windows.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 /* USB path is a string of at most 8 decimal numbers < 128 separated by dots */
25 #define MAX_USB_PATH  (8*3 + 7*1 + 1)
26
27 /* The stuff below is not yet available in MinGW apparently. Define it here. */
28
29 #ifndef USB_NODE_CONNECTION_INFORMATION_EX
30 typedef struct _USB_NODE_CONNECTION_INFORMATION_EX {
31         ULONG ConnectionIndex;
32         USB_DEVICE_DESCRIPTOR DeviceDescriptor;
33         UCHAR CurrentConfigurationValue;
34         UCHAR Speed;
35         BOOLEAN DeviceIsHub;
36         USHORT DeviceAddress;
37         ULONG NumberOfOpenPipes;
38         USB_CONNECTION_STATUS ConnectionStatus;
39         USB_PIPE_INFO PipeList[];
40 } USB_NODE_CONNECTION_INFORMATION_EX, *PUSB_NODE_CONNECTION_INFORMATION_EX;
41 #endif
42
43 #ifndef USB_GET_NODE_CONNECTION_INFORMATION_EX
44 #define USB_GET_NODE_CONNECTION_INFORMATION_EX 274
45 #endif
46
47 #ifndef IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX
48 #define IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX \
49         CTL_CODE(FILE_DEVICE_USB, USB_GET_NODE_CONNECTION_INFORMATION_EX, \
50         METHOD_BUFFERED, FILE_ANY_ACCESS)
51 #endif
52
53 #ifndef CM_DRP_COMPATIBLEIDS
54 #define CM_DRP_COMPATIBLEIDS 0x03
55 #endif
56 #ifndef CM_DRP_CLASS
57 #define CM_DRP_CLASS 0x08
58 #endif
59 #ifndef CM_DRP_FRIENDLYNAME
60 #define CM_DRP_FRIENDLYNAME 0x0d
61 #endif
62 #ifndef CM_DRP_ADDRESS
63 #define CM_DRP_ADDRESS 0x1d
64 #endif
65
66 #ifndef CM_Get_DevNode_Registry_PropertyA
67 CMAPI CONFIGRET WINAPI CM_Get_DevNode_Registry_PropertyA(DEVINST dnDevInst, \
68         ULONG ulProperty, PULONG pulRegDataType, PVOID Buffer, \
69         PULONG pulLength, ULONG ulFlags);
70 #endif
71
72 static void enumerate_hub(struct sp_port *port, char *hub_name,
73                           char *parent_path);
74
75 static char *wc_to_utf8(PWCHAR wc_buffer, ULONG size)
76 {
77         WCHAR wc_str[size/sizeof(WCHAR)+1];
78         char *utf8_str;
79
80         /* zero terminate the wide char string */
81         memcpy(wc_str, wc_buffer, size);
82         wc_str[sizeof(wc_str)-1] = 0;
83
84         /* compute the size of the utf8 converted string */
85         if (!(size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
86                                          NULL, 0, NULL, NULL)))
87                 return NULL;
88
89         /* allocate utf8 output buffer */
90         if (!(utf8_str = malloc(size)))
91                 return NULL;
92
93         /* actually converted to utf8 */
94         if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
95                                  utf8_str, size, NULL, NULL)) {
96                 free(utf8_str);
97                 return NULL;
98         }
99
100         return utf8_str;
101 }
102
103 static char *get_root_hub_name(HANDLE host_controller)
104 {
105         USB_ROOT_HUB_NAME  root_hub_name;
106         PUSB_ROOT_HUB_NAME root_hub_name_wc;
107         char *root_hub_name_utf8;
108         ULONG size = 0;
109
110         /* compute the size of the root hub name string */
111         if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0,
112                              &root_hub_name, sizeof(root_hub_name), &size, NULL))
113                 return NULL;
114
115         /* allocate wide char root hub name string */
116         size = root_hub_name.ActualLength;
117         if (!(root_hub_name_wc = malloc(size)))
118                 return NULL;
119
120         /* actually get the root hub name string */
121         if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME,
122                              NULL, 0, root_hub_name_wc, size, &size, NULL)) {
123                 free(root_hub_name_wc);
124                 return NULL;
125         }
126
127         /* convert the root hub name string to utf8 */
128         root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size);
129         free(root_hub_name_wc);
130         return root_hub_name_utf8;
131 }
132
133 static char *get_external_hub_name(HANDLE hub, ULONG connection_index)
134 {
135         USB_NODE_CONNECTION_NAME  ext_hub_name;
136         PUSB_NODE_CONNECTION_NAME ext_hub_name_wc;
137         char *ext_hub_name_utf8;
138         ULONG size;
139
140         /* compute the size of the external hub name string */
141         ext_hub_name.ConnectionIndex = connection_index;
142         if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
143                              &ext_hub_name, sizeof(ext_hub_name),
144                              &ext_hub_name, sizeof(ext_hub_name), &size, NULL))
145                 return NULL;
146
147         /* allocate wide char external hub name string */
148         size = ext_hub_name.ActualLength;
149         if (size <= sizeof(ext_hub_name)
150             || !(ext_hub_name_wc = malloc(size)))
151                 return NULL;
152
153         /* get the name of the external hub attached to the specified port */
154         ext_hub_name_wc->ConnectionIndex = connection_index;
155         if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
156                              ext_hub_name_wc, size,
157                              ext_hub_name_wc, size, &size, NULL)) {
158                 free(ext_hub_name_wc);
159                 return NULL;
160         }
161
162         /* convert the external hub name string to utf8 */
163         ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size);
164         free(ext_hub_name_wc);
165         return ext_hub_name_utf8;
166 }
167
168 static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index,
169                                    UCHAR descriptor_index)
170 {
171         char desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) +
172                           MAXIMUM_USB_STRING_LENGTH] = { 0 };
173         PUSB_DESCRIPTOR_REQUEST desc_req = (void *) desc_req_buf;
174         PUSB_STRING_DESCRIPTOR  desc     = (void *) (desc_req + 1);
175         ULONG size = sizeof(desc_req_buf);
176
177         desc_req->ConnectionIndex     = connection_index;
178         desc_req->SetupPacket.wValue  = (USB_STRING_DESCRIPTOR_TYPE << 8)
179                                         | descriptor_index;
180         desc_req->SetupPacket.wIndex  = 0;
181         desc_req->SetupPacket.wLength = size - sizeof(*desc_req);
182
183         if (!DeviceIoControl(hub_device,
184                              IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
185                              desc_req, size, desc_req, size, &size, NULL)
186             || size < 2
187             || desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE
188             || desc->bLength != size - sizeof(*desc_req)
189             || desc->bLength % 2)
190                 return NULL;
191
192         return wc_to_utf8(desc->bString, desc->bLength);
193 }
194
195 static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device,
196                                 ULONG nb_ports, char *parent_path)
197 {
198         char path[MAX_USB_PATH];
199         ULONG index = 0;
200
201         for (index = 1; index <= nb_ports; index++) {
202                 PUSB_NODE_CONNECTION_INFORMATION_EX connection_info_ex;
203                 ULONG size = sizeof(*connection_info_ex) + 30*sizeof(USB_PIPE_INFO);
204
205                 if (!(connection_info_ex = malloc(size)))
206                         break;
207
208                 connection_info_ex->ConnectionIndex = index;
209                 if (!DeviceIoControl(hub_device,
210                                      IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
211                                      connection_info_ex, size,
212                                      connection_info_ex, size, &size, NULL)) {
213                         /* try to get CONNECTION_INFORMATION if CONNECTION_INFORMATION_EX
214                            did not work */
215                         PUSB_NODE_CONNECTION_INFORMATION connection_info;
216
217                         size = sizeof(*connection_info) + 30*sizeof(USB_PIPE_INFO);
218                         if (!(connection_info = malloc(size))) {
219                                 free(connection_info_ex);
220                                 continue;
221                         }
222                         connection_info->ConnectionIndex = index;
223                         if (!DeviceIoControl(hub_device,
224                                              IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
225                                              connection_info, size,
226                                              connection_info, size, &size, NULL)) {
227                                 free(connection_info);
228                                 free(connection_info_ex);
229                                 continue;
230                         }
231
232                         connection_info_ex->ConnectionIndex = connection_info->ConnectionIndex;
233                         connection_info_ex->DeviceDescriptor = connection_info->DeviceDescriptor;
234                         connection_info_ex->DeviceIsHub = connection_info->DeviceIsHub;
235                         connection_info_ex->DeviceAddress = connection_info->DeviceAddress;
236                         free(connection_info);
237                 }
238
239                 if (connection_info_ex->DeviceIsHub) {
240                         /* recursively enumerate external hub */
241                         PCHAR ext_hub_name;
242                         if ((ext_hub_name = get_external_hub_name(hub_device, index))) {
243                                 snprintf(path, sizeof(path), "%s%ld.",
244                                          parent_path, connection_info_ex->ConnectionIndex);
245                                 enumerate_hub(port, ext_hub_name, path);
246                         }
247                         free(connection_info_ex);
248                 } else {
249                         snprintf(path, sizeof(path), "%s%ld",
250                                  parent_path, connection_info_ex->ConnectionIndex);
251
252                         /* check if this device is the one we search for */
253                         if (strcmp(path, port->usb_path)) {
254                                 free(connection_info_ex);
255                                 continue;
256                         }
257
258                         /* finally grab detailed informations regarding the device */
259                         port->usb_address = connection_info_ex->DeviceAddress + 1;
260                         port->usb_vid = connection_info_ex->DeviceDescriptor.idVendor;
261                         port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct;
262
263                         if (connection_info_ex->DeviceDescriptor.iManufacturer)
264                                 port->usb_manufacturer = get_string_descriptor(hub_device,index,
265                                            connection_info_ex->DeviceDescriptor.iManufacturer);
266                         if (connection_info_ex->DeviceDescriptor.iProduct)
267                                 port->usb_product = get_string_descriptor(hub_device, index,
268                                            connection_info_ex->DeviceDescriptor.iProduct);
269                         if (connection_info_ex->DeviceDescriptor.iSerialNumber)
270                                 port->usb_serial = get_string_descriptor(hub_device, index,
271                                            connection_info_ex->DeviceDescriptor.iSerialNumber);
272
273                         free(connection_info_ex);
274                         break;
275                 }
276         }
277 }
278
279 static void enumerate_hub(struct sp_port *port, char *hub_name,
280                           char *parent_path)
281 {
282         USB_NODE_INFORMATION hub_info;
283         HANDLE hub_device;
284         ULONG size = sizeof(hub_info);
285         char *device_name;
286
287         /* open the hub with its full name */
288         if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1)))
289                 return;
290         strcpy(device_name, "\\\\.\\");
291         strcat(device_name, hub_name);
292         hub_device = CreateFile(device_name, GENERIC_WRITE, FILE_SHARE_WRITE,
293                                 NULL, OPEN_EXISTING, 0, NULL);
294         free(device_name);
295         if (hub_device == INVALID_HANDLE_VALUE)
296                 return;
297
298         /* get the number of ports of the hub */
299         if (DeviceIoControl(hub_device, IOCTL_USB_GET_NODE_INFORMATION,
300                             &hub_info, size, &hub_info, size, &size, NULL))
301                 /* enumarate the ports of the hub */
302                 enumerate_hub_ports(port, hub_device,
303                    hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts, parent_path);
304
305         CloseHandle(hub_device);
306 }
307
308 static void enumerate_host_controller(struct sp_port *port,
309                                       HANDLE host_controller_device)
310 {
311         char *root_hub_name;
312
313         if ((root_hub_name = get_root_hub_name(host_controller_device))) {
314                 enumerate_hub(port, root_hub_name, "");
315                 free(root_hub_name);
316         }
317 }
318
319 static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match)
320 {
321         HDEVINFO device_info;
322         SP_DEVINFO_DATA device_info_data;
323         ULONG i, size = 0;
324
325         device_info = SetupDiGetClassDevs(&GUID_CLASS_USB_HOST_CONTROLLER,NULL,NULL,
326                                           DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
327         device_info_data.cbSize = sizeof(device_info_data);
328
329         for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
330                 SP_DEVICE_INTERFACE_DATA device_interface_data;
331                 PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data;
332                 DEVINST dev_inst = dev_inst_match;
333                 HANDLE host_controller_device;
334
335                 device_interface_data.cbSize = sizeof(device_interface_data);
336                 if (!SetupDiEnumDeviceInterfaces(device_info, 0,
337                                                  &GUID_CLASS_USB_HOST_CONTROLLER,
338                                                  i, &device_interface_data))
339                         continue;
340
341                 if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
342                                                      NULL, 0, &size, NULL)
343                     && GetLastError() != ERROR_INSUFFICIENT_BUFFER)
344                         continue;
345
346                 if (!(device_detail_data = malloc(size)))
347                         continue;
348                 device_detail_data->cbSize = sizeof(*device_detail_data);
349                 if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
350                                                      device_detail_data, size, &size,
351                                                      NULL)) {
352                         free(device_detail_data);
353                         continue;
354                 }
355
356                 while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS
357                        && dev_inst != device_info_data.DevInst) { }
358                 if (dev_inst != device_info_data.DevInst) {
359                         free(device_detail_data);
360                         continue;
361                 }
362
363                 port->usb_bus = i + 1;
364
365                 host_controller_device = CreateFile(device_detail_data->DevicePath,
366                                                     GENERIC_WRITE, FILE_SHARE_WRITE,
367                                                     NULL, OPEN_EXISTING, 0, NULL);
368                 if (host_controller_device != INVALID_HANDLE_VALUE) {
369                         enumerate_host_controller(port, host_controller_device);
370                         CloseHandle(host_controller_device);
371                 }
372                 free(device_detail_data);
373         }
374
375         SetupDiDestroyDeviceInfoList(device_info);
376         return;
377 }
378
379 SP_PRIV enum sp_return get_port_details(struct sp_port *port)
380 {
381         /* Description limited to 127 char,
382            anything longer would not be user friendly anyway */
383         char description[128];
384         SP_DEVINFO_DATA device_info_data = { .cbSize = sizeof(device_info_data) };
385         HDEVINFO device_info;
386         int i;
387
388         device_info = SetupDiGetClassDevs(NULL, 0, 0,
389                                           DIGCF_PRESENT | DIGCF_ALLCLASSES);
390         if (device_info == INVALID_HANDLE_VALUE)
391                 RETURN_FAIL("SetupDiGetClassDevs() failed");
392
393         for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
394                 HKEY device_key;
395                 DEVINST dev_inst;
396                 char value[8], class[16];
397                 DWORD size, type;
398                 CONFIGRET cr;
399
400                 /* check if this is the device we are looking for */
401                 if (!(device_key = SetupDiOpenDevRegKey(device_info, &device_info_data,
402                                                         DICS_FLAG_GLOBAL, 0,
403                                                         DIREG_DEV, KEY_QUERY_VALUE)))
404                         continue;
405                 size = sizeof(value);
406                 if (RegQueryValueExA(device_key, "PortName", NULL, &type, (LPBYTE)value,
407                                      &size) != ERROR_SUCCESS || type != REG_SZ)
408                         continue;
409                 RegCloseKey(device_key);
410                 value[sizeof(value)-1] = 0;
411                 if (strcmp(value, port->name))
412                         continue;
413
414                 /* check port transport type */
415                 dev_inst = device_info_data.DevInst;
416                 size = sizeof(class);
417                 cr = CR_FAILURE;
418                 while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS &&
419                        (cr = CM_Get_DevNode_Registry_PropertyA(dev_inst,
420                                  CM_DRP_CLASS, 0, class, &size, 0)) != CR_SUCCESS) { }
421                 if (cr == CR_SUCCESS) {
422                         if (!strcmp(class, "USB"))
423                                 port->transport = SP_TRANSPORT_USB;
424                 }
425
426                 /* get port description (friendly name) */
427                 dev_inst = device_info_data.DevInst;
428                 size = sizeof(description);
429                 while ((cr = CM_Get_DevNode_Registry_PropertyA(dev_inst,
430                           CM_DRP_FRIENDLYNAME, 0, description, &size, 0)) != CR_SUCCESS
431                        && CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) { }
432                 if (cr == CR_SUCCESS)
433                         port->description = strdup(description);
434
435                 /* get more informations for USB connected ports */
436                 if (port->transport == SP_TRANSPORT_USB) {
437                         char usb_path[MAX_USB_PATH] = "", tmp[MAX_USB_PATH];
438                         char device_id[MAX_DEVICE_ID_LEN];
439
440                         /* recurse over parents to build the USB device path */
441                         dev_inst = device_info_data.DevInst;
442                         do {
443                                 /* verify that this layer of the tree is USB related */
444                                 if (CM_Get_Device_IDA(dev_inst, device_id,
445                                                       sizeof(device_id), 0) != CR_SUCCESS
446                                     || strncmp(device_id, "USB\\", 4))
447                                         continue;
448
449                                 /* discard one layer for composite devices */
450                                 char compat_ids[512], *p = compat_ids;
451                                 size = sizeof(compat_ids);
452                                 if (CM_Get_DevNode_Registry_PropertyA(dev_inst,
453                                                                       CM_DRP_COMPATIBLEIDS, 0,
454                                                                       &compat_ids,
455                                                                       &size, 0) == CR_SUCCESS) {
456                                         while (*p) {
457                                                 if (!strncmp(p, "USB\\COMPOSITE", 13))
458                                                         break;
459                                                 p += strlen(p) + 1;
460                                         }
461                                         if (*p)
462                                                 continue;
463                                 }
464
465                                 /* stop the recursion when reaching the USB root */
466                                 if (!strncmp(device_id, "USB\\ROOT", 8))
467                                         break;
468
469                                 /* prepend the address of current USB layer to the USB path */
470                                 DWORD address;
471                                 size = sizeof(address);
472                                 if (CM_Get_DevNode_Registry_PropertyA(dev_inst, CM_DRP_ADDRESS,
473                                                         0, &address, &size, 0) == CR_SUCCESS) {
474                                         strcpy(tmp, usb_path);
475                                         snprintf(usb_path, sizeof(usb_path), "%d%s%s",
476                                                  (int)address, *tmp ? "." : "", tmp);
477                                 }
478                         } while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS);
479
480                         port->usb_path = strdup(usb_path);
481
482                         /* wake up the USB device to be able to read string descriptor */
483                         char *escaped_port_name;
484                         HANDLE handle;
485                         if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
486                                 RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
487                         sprintf(escaped_port_name, "\\\\.\\%s", port->name);
488                         handle = CreateFile(escaped_port_name, GENERIC_READ, 0, 0,
489                                             OPEN_EXISTING,
490                                             FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
491                         free(escaped_port_name);
492                         CloseHandle(handle);
493
494                         /* retrive USB device details from the device descriptor */
495                         get_usb_details(port, device_info_data.DevInst);
496                 }
497                 break;
498         }
499
500         RETURN_OK();
501 }
502
503 SP_PRIV enum sp_return list_ports(struct sp_port ***list)
504 {
505         HKEY key;
506         TCHAR *value, *data;
507         DWORD max_value_len, max_data_size, max_data_len;
508         DWORD value_len, data_size, data_len;
509         DWORD type, index = 0;
510         char *name;
511         int name_len;
512         int ret = SP_OK;
513
514         DEBUG("Opening registry key");
515         if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
516                         0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
517                 SET_FAIL(ret, "RegOpenKeyEx() failed");
518                 goto out_done;
519         }
520         DEBUG("Querying registry key value and data sizes");
521         if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
522                                 &max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) {
523                 SET_FAIL(ret, "RegQueryInfoKey() failed");
524                 goto out_close;
525         }
526         max_data_len = max_data_size / sizeof(TCHAR);
527         if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) {
528                 SET_ERROR(ret, SP_ERR_MEM, "registry value malloc failed");
529                 goto out_close;
530         }
531         if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) {
532                 SET_ERROR(ret, SP_ERR_MEM, "registry data malloc failed");
533                 goto out_free_value;
534         }
535         DEBUG("Iterating over values");
536         while (
537                 value_len = max_value_len + 1,
538                 data_size = max_data_size,
539                 RegEnumValue(key, index, value, &value_len,
540                         NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
541         {
542                 data_len = data_size / sizeof(TCHAR);
543                 data[data_len] = '\0';
544 #ifdef UNICODE
545                 name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
546 #else
547                 name_len = data_len + 1;
548 #endif
549                 if (!(name = malloc(name_len))) {
550                         SET_ERROR(ret, SP_ERR_MEM, "registry port name malloc failed");
551                         goto out;
552                 }
553 #ifdef UNICODE
554                 WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
555 #else
556                 strcpy(name, data);
557 #endif
558                 if (type == REG_SZ) {
559                         DEBUG("Found port %s", name);
560                         if (!(*list = list_append(*list, name))) {
561                                 SET_ERROR(ret, SP_ERR_MEM, "list append failed");
562                                 goto out;
563                         }
564                 }
565                 index++;
566         }
567 out:
568         free(data);
569 out_free_value:
570         free(value);
571 out_close:
572         RegCloseKey(key);
573 out_done:
574
575         return ret;
576 }