Vendor go-serial.

This commit is contained in:
Hendrik van Wyk
2017-09-16 15:25:31 +02:00
parent 44891b1795
commit 33ad6b8d1d
11 changed files with 6614 additions and 0 deletions

81
vendor/github.com/mikepb/go-serial/README.md generated vendored Normal file
View File

@@ -0,0 +1,81 @@
# Go Serial
[![GoDoc](https://godoc.org/github.com/mikepb/go-serial?status.svg)](https://godoc.org/github.com/mikepb/go-serial)
Package serial provides a binding to libserialport for serial port
functionality. Serial ports are commonly used with embedded systems,
such as the Arduino platform.
## Usage
```go
package main
import (
"github.com/mikepb/go-serial"
"log"
)
func main() {
options := serial.RawOptions
options.BitRate = 115200
p, err := options.Open("/dev/tty")
if err != nil {
log.Panic(err)
}
defer p.Close()
buf := make([]byte, 1)
if c, err := p.Read(buf); err != nil {
log.Panic(err)
} else {
log.Println(buf)
}
}
```
## Documentation
https://godoc.org/github.com/mikepb/go-serial
## License
Copyright 2014 Michael Phan-Ba
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Files from the libserialport library are licensed under the GNU Lesser General
Public License. These files include in the header the notice that follows.
This file is part of the libserialport project.
Copyright (C) 2010-2012 Bert Vermeulen <bert@biot.com>
Copyright (C) 2010-2012 Uwe Hermann <uwe@hermann-uwe.de>
Copyright (C) 2013-2014 Martin Ling <martin-libserialport@earth.li>
Copyright (C) 2013 Matthias Heidbrink <m-sigrok@heidbrink.biz>
Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

1430
vendor/github.com/mikepb/go-serial/libserialport.h generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,229 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2014 Martin Ling <martin-libserialport@earth.li>
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __linux__
#define _BSD_SOURCE // for timeradd, timersub, timercmp
#endif
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef _WIN32
#include <windows.h>
#include <tchar.h>
#include <setupapi.h>
#include <cfgmgr32.h>
#undef DEFINE_GUID
#define DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
static const GUID name = { l,w1,w2,{ b1,b2,b3,b4,b5,b6,b7,b8 } }
#include <usbioctl.h>
#include <usbiodef.h>
#else
#include <limits.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <limits.h>
#include <poll.h>
#endif
#ifdef __APPLE__
#include <CoreFoundation/CoreFoundation.h>
#include <IOKit/IOKitLib.h>
#include <IOKit/serial/IOSerialKeys.h>
#include <IOKit/serial/ioss.h>
#include <sys/syslimits.h>
#endif
#ifdef __linux__
#include <dirent.h>
#ifndef __ANDROID__
#include "linux/serial.h"
#endif
#include "linux_termios.h"
/* TCGETX/TCSETX is not available everywhere. */
#if defined(TCGETX) && defined(TCSETX) && defined(HAVE_TERMIOX)
#define USE_TERMIOX
#endif
#endif
/* TIOCINQ/TIOCOUTQ is not available everywhere. */
#if !defined(TIOCINQ) && defined(FIONREAD)
#define TIOCINQ FIONREAD
#endif
#if !defined(TIOCOUTQ) && defined(FIONWRITE)
#define TIOCOUTQ FIONWRITE
#endif
/* Non-standard baudrates are not available everywhere. */
#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && defined(HAVE_BOTHER)
#define USE_TERMIOS_SPEED
#endif
struct sp_port {
char *name;
char *description;
enum sp_transport transport;
int usb_bus;
int usb_address;
int usb_vid;
int usb_pid;
char *usb_manufacturer;
char *usb_product;
char *usb_serial;
char *bluetooth_address;
#ifdef _WIN32
char *usb_path;
HANDLE hdl;
COMMTIMEOUTS timeouts;
OVERLAPPED write_ovl;
OVERLAPPED read_ovl;
OVERLAPPED wait_ovl;
DWORD events;
BYTE pending_byte;
BOOL writing;
#else
int fd;
#endif
};
struct sp_port_config {
int baudrate;
int bits;
enum sp_parity parity;
int stopbits;
enum sp_rts rts;
enum sp_cts cts;
enum sp_dtr dtr;
enum sp_dsr dsr;
enum sp_xonxoff xon_xoff;
};
struct port_data {
#ifdef _WIN32
DCB dcb;
#else
struct termios term;
int controlbits;
int termiox_supported;
int rts_flow;
int cts_flow;
int dtr_flow;
int dsr_flow;
#endif
};
#ifdef _WIN32
typedef HANDLE event_handle;
#else
typedef int event_handle;
#endif
/* Standard baud rates. */
#ifdef _WIN32
#define BAUD_TYPE DWORD
#define BAUD(n) {CBR_##n, n}
#else
#define BAUD_TYPE speed_t
#define BAUD(n) {B##n, n}
#endif
struct std_baudrate {
BAUD_TYPE index;
int value;
};
extern const struct std_baudrate std_baudrates[];
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#define NUM_STD_BAUDRATES ARRAY_SIZE(std_baudrates)
extern void (*sp_debug_handler)(const char *format, ...);
/* Debug output macros. */
#define DEBUG_FMT(fmt, ...) do { \
if (sp_debug_handler) \
sp_debug_handler(fmt ".\n", __VA_ARGS__); \
} while (0)
#define DEBUG(msg) DEBUG_FMT(msg, NULL)
#define DEBUG_ERROR(err, msg) DEBUG_FMT("%s returning " #err ": " msg, __func__)
#define DEBUG_FAIL(msg) do { \
char *errmsg = sp_last_error_message(); \
DEBUG_FMT("%s returning SP_ERR_FAIL: " msg ": %s", __func__, errmsg); \
sp_free_error_message(errmsg); \
} while (0);
#define RETURN() do { \
DEBUG_FMT("%s returning", __func__); \
return; \
} while(0)
#define RETURN_CODE(x) do { \
DEBUG_FMT("%s returning " #x, __func__); \
return x; \
} while (0)
#define RETURN_CODEVAL(x) do { \
switch (x) { \
case SP_OK: RETURN_CODE(SP_OK); \
case SP_ERR_ARG: RETURN_CODE(SP_ERR_ARG); \
case SP_ERR_FAIL: RETURN_CODE(SP_ERR_FAIL); \
case SP_ERR_MEM: RETURN_CODE(SP_ERR_MEM); \
case SP_ERR_SUPP: RETURN_CODE(SP_ERR_SUPP); \
} \
} while (0)
#define RETURN_OK() RETURN_CODE(SP_OK);
#define RETURN_ERROR(err, msg) do { \
DEBUG_ERROR(err, msg); \
return err; \
} while (0)
#define RETURN_FAIL(msg) do { \
DEBUG_FAIL(msg); \
return SP_ERR_FAIL; \
} while (0)
#define RETURN_INT(x) do { \
int _x = x; \
DEBUG_FMT("%s returning %d", __func__, _x); \
return _x; \
} while (0)
#define RETURN_STRING(x) do { \
char *_x = x; \
DEBUG_FMT("%s returning %s", __func__, _x); \
return _x; \
} while (0)
#define RETURN_POINTER(x) do { \
void *_x = x; \
DEBUG_FMT("%s returning %p", __func__, _x); \
return _x; \
} while (0)
#define SET_ERROR(val, err, msg) do { DEBUG_ERROR(err, msg); val = err; } while (0)
#define SET_FAIL(val, msg) do { DEBUG_FAIL(msg); val = SP_ERR_FAIL; } while (0)
#define TRACE(fmt, ...) DEBUG_FMT("%s(" fmt ") called", __func__, __VA_ARGS__)
#define TRACE_VOID() DEBUG_FMT("%s() called", __func__)
#define TRY(x) do { int ret = x; if (ret != SP_OK) RETURN_CODEVAL(ret); } while (0)
SP_PRIV struct sp_port **list_append(struct sp_port **list, const char *portname);
/* OS-specific Helper functions. */
SP_PRIV enum sp_return get_port_details(struct sp_port *port);
SP_PRIV enum sp_return list_ports(struct sp_port ***list);

226
vendor/github.com/mikepb/go-serial/linux.c generated vendored Normal file
View File

@@ -0,0 +1,226 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __linux__
#include "libserialport.h"
#include "libserialport_internal.h"
SP_PRIV enum sp_return get_port_details(struct sp_port *port)
{
/* Description limited to 127 char,
anything longer would not be user friendly anyway */
char description[128];
int bus, address;
unsigned int vid, pid;
char manufacturer[128], product[128], serial[128];
char baddr[32];
const char dir_name[] = "/sys/class/tty/%s/device/%s%s";
char sub_dir[32] = "", file_name[PATH_MAX];
char *ptr, *dev = port->name + 5;
FILE *file;
int i, count;
if (strncmp(port->name, "/dev/", 5))
RETURN_ERROR(SP_ERR_ARG, "Device name not recognized.");
snprintf(file_name, sizeof(file_name), "/sys/class/tty/%s", dev);
count = readlink(file_name, file_name, sizeof(file_name));
if (count <= 0 || count >= (int) sizeof(file_name)-1)
RETURN_ERROR(SP_ERR_ARG, "Device not found.");
file_name[count] = 0;
if (strstr(file_name, "bluetooth"))
port->transport = SP_TRANSPORT_BLUETOOTH;
else if (strstr(file_name, "usb"))
port->transport = SP_TRANSPORT_USB;
if (port->transport == SP_TRANSPORT_USB) {
for (i=0; i<5; i++) {
strcat(sub_dir, "../");
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "busnum");
if (!(file = fopen(file_name, "r")))
continue;
count = fscanf(file, "%d", &bus);
fclose(file);
if (count != 1)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "devnum");
if (!(file = fopen(file_name, "r")))
continue;
count = fscanf(file, "%d", &address);
fclose(file);
if (count != 1)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "idVendor");
if (!(file = fopen(file_name, "r")))
continue;
count = fscanf(file, "%4x", &vid);
fclose(file);
if (count != 1)
continue;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "idProduct");
if (!(file = fopen(file_name, "r")))
continue;
count = fscanf(file, "%4x", &pid);
fclose(file);
if (count != 1)
continue;
port->usb_bus = bus;
port->usb_address = address;
port->usb_vid = vid;
port->usb_pid = pid;
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "product");
if ((file = fopen(file_name, "r"))) {
if ((ptr = fgets(description, sizeof(description), file))) {
ptr = description + strlen(description) - 1;
if (ptr >= description && *ptr == '\n')
*ptr = 0;
port->description = strdup(description);
}
fclose(file);
}
if (!file || !ptr)
port->description = strdup(dev);
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "manufacturer");
if ((file = fopen(file_name, "r"))) {
if ((ptr = fgets(manufacturer, sizeof(manufacturer), file))) {
ptr = manufacturer + strlen(manufacturer) - 1;
if (ptr >= manufacturer && *ptr == '\n')
*ptr = 0;
port->usb_manufacturer = strdup(manufacturer);
}
fclose(file);
}
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "product");
if ((file = fopen(file_name, "r"))) {
if ((ptr = fgets(product, sizeof(product), file))) {
ptr = product + strlen(product) - 1;
if (ptr >= product && *ptr == '\n')
*ptr = 0;
port->usb_product = strdup(product);
}
fclose(file);
}
snprintf(file_name, sizeof(file_name), dir_name, dev, sub_dir, "serial");
if ((file = fopen(file_name, "r"))) {
if ((ptr = fgets(serial, sizeof(serial), file))) {
ptr = serial + strlen(serial) - 1;
if (ptr >= serial && *ptr == '\n')
*ptr = 0;
port->usb_serial = strdup(serial);
}
fclose(file);
}
break;
}
} else {
port->description = strdup(dev);
if (port->transport == SP_TRANSPORT_BLUETOOTH) {
snprintf(file_name, sizeof(file_name), dir_name, dev, "", "address");
if ((file = fopen(file_name, "r"))) {
if ((ptr = fgets(baddr, sizeof(baddr), file))) {
ptr = baddr + strlen(baddr) - 1;
if (ptr >= baddr && *ptr == '\n')
*ptr = 0;
port->bluetooth_address = strdup(baddr);
}
fclose(file);
}
}
}
RETURN_OK();
}
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
char name[PATH_MAX], target[PATH_MAX];
struct dirent entry, *result;
#ifdef HAVE_SERIAL_STRUCT
struct serial_struct serial_info;
int ioctl_result;
#endif
char buf[sizeof(entry.d_name) + 16];
int len, fd;
DIR *dir;
int ret = SP_OK;
DEBUG("Enumerating tty devices");
if (!(dir = opendir("/sys/class/tty")))
RETURN_FAIL("could not open /sys/class/tty");
DEBUG("Iterating over results");
while (!readdir_r(dir, &entry, &result) && result) {
snprintf(buf, sizeof(buf), "/sys/class/tty/%s", entry.d_name);
len = readlink(buf, target, sizeof(target));
if (len <= 0 || len >= (int) sizeof(target)-1)
continue;
target[len] = 0;
if (strstr(target, "virtual"))
continue;
snprintf(name, sizeof(name), "/dev/%s", entry.d_name);
DEBUG_FMT("Found device %s", name);
if (strstr(target, "serial8250")) {
/* The serial8250 driver has a hardcoded number of ports.
* The only way to tell which actually exist on a given system
* is to try to open them and make an ioctl call. */
DEBUG("serial8250 device, attempting to open");
if ((fd = open(name, O_RDWR | O_NONBLOCK | O_NOCTTY)) < 0) {
DEBUG("open failed, skipping");
continue;
}
#ifdef HAVE_SERIAL_STRUCT
ioctl_result = ioctl(fd, TIOCGSERIAL, &serial_info);
#endif
close(fd);
#ifdef HAVE_SERIAL_STRUCT
if (ioctl_result != 0) {
DEBUG("ioctl failed, skipping");
continue;
}
if (serial_info.type == PORT_UNKNOWN) {
DEBUG("port type is unknown, skipping");
continue;
}
#endif
}
DEBUG_FMT("Found port %s", name);
*list = list_append(*list, name);
if (!list) {
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
break;
}
}
closedir(dir);
return ret;
}
#endif

132
vendor/github.com/mikepb/go-serial/linux_termios.c generated vendored Normal file
View File

@@ -0,0 +1,132 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* At the time of writing, glibc does not support the Linux kernel interfaces
* for setting non-standard baud rates and flow control. We therefore have to
* prepare the correct ioctls ourselves, for which we need the declarations in
* linux/termios.h.
*
* We can't include linux/termios.h in serialport.c however, because its
* contents conflict with the termios.h provided by glibc. So this file exists
* to isolate the bits of code which use the kernel termios declarations.
*
* The details vary by architecture. Some architectures have c_ispeed/c_ospeed
* in struct termios, accessed with TCSETS/TCGETS. Others have these fields in
* struct termios2, accessed with TCSETS2/TCGETS2. Some architectures have the
* TCSETX/TCGETX ioctls used with struct termiox, others do not.
*/
#ifdef __linux__
#include <stdlib.h>
#include <linux/termios.h>
#include "linux_termios.h"
SP_PRIV unsigned long get_termios_get_ioctl(void)
{
#ifdef HAVE_TERMIOS2
return TCGETS2;
#else
return TCGETS;
#endif
}
SP_PRIV unsigned long get_termios_set_ioctl(void)
{
#ifdef HAVE_TERMIOS2
return TCSETS2;
#else
return TCSETS;
#endif
}
SP_PRIV size_t get_termios_size(void)
{
#ifdef HAVE_TERMIOS2
return sizeof(struct termios2);
#else
return sizeof(struct termios);
#endif
}
#if (defined(HAVE_TERMIOS_SPEED) || defined(HAVE_TERMIOS2_SPEED)) && defined(HAVE_BOTHER)
SP_PRIV int get_termios_speed(void *data)
{
#ifdef HAVE_TERMIOS2
struct termios2 *term = (struct termios2 *) data;
#else
struct termios *term = (struct termios *) data;
#endif
if (term->c_ispeed != term->c_ospeed)
return -1;
else
return term->c_ispeed;
}
SP_PRIV void set_termios_speed(void *data, int speed)
{
#ifdef HAVE_TERMIOS2
struct termios2 *term = (struct termios2 *) data;
#else
struct termios *term = (struct termios *) data;
#endif
term->c_cflag &= ~CBAUD;
term->c_cflag |= BOTHER;
term->c_ispeed = term->c_ospeed = speed;
}
#endif
#ifdef HAVE_TERMIOX
SP_PRIV size_t get_termiox_size(void)
{
return sizeof(struct termiox);
}
SP_PRIV int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr)
{
struct termiox *termx = (struct termiox *) data;
int flags = 0;
*rts = (termx->x_cflag & RTSXOFF);
*cts = (termx->x_cflag & CTSXON);
*dtr = (termx->x_cflag & DTRXOFF);
*dsr = (termx->x_cflag & DSRXON);
return flags;
}
SP_PRIV void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr)
{
struct termiox *termx = (struct termiox *) data;
termx->x_cflag &= ~(RTSXOFF | CTSXON | DTRXOFF | DSRXON);
if (rts)
termx->x_cflag |= RTSXOFF;
if (cts)
termx->x_cflag |= CTSXON;
if (dtr)
termx->x_cflag |= DTRXOFF;
if (dsr)
termx->x_cflag |= DSRXON;
}
#endif
#endif

38
vendor/github.com/mikepb/go-serial/linux_termios.h generated vendored Normal file
View File

@@ -0,0 +1,38 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2013 Martin Ling <martin-libserialport@earth.li>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __linux__
#ifndef LIBSERIALPORT_LINUX_TERMIOS_H
#define LIBSERIALPORT_LINUX_TERMIOS_H
#include <stdlib.h>
SP_PRIV unsigned long get_termios_get_ioctl(void);
SP_PRIV unsigned long get_termios_set_ioctl(void);
SP_PRIV size_t get_termios_size(void);
SP_PRIV int get_termios_speed(void *data);
SP_PRIV void set_termios_speed(void *data, int speed);
SP_PRIV size_t get_termiox_size(void);
SP_PRIV int get_termiox_flow(void *data, int *rts, int *cts, int *dtr, int *dsr);
SP_PRIV void set_termiox_flow(void *data, int rts, int cts, int dtr, int dsr);
#endif
#endif

View File

@@ -0,0 +1,213 @@
package main
import (
".."
"log"
"time"
)
func main() {
ports, err := serial.ListPorts()
if err != nil {
log.Panic(err)
}
log.Printf("Found %d ports:\n", len(ports))
for _, info := range ports {
log.Println(info.Name())
log.Println("\tName:", info.Name())
log.Println("\tDescription:", info.Description())
log.Println("\tTransport:", info.Transport())
if bus, addr, err := info.USBBusAddress(); err != nil {
log.Println("\tbus:", bus, "\taddr:", addr)
} else {
log.Println(err)
}
if vid, pid, err := info.USBVIDPID(); err != nil {
log.Println("\tvid:", vid, "\tpid:", pid)
} else {
log.Println(err)
}
log.Println("\tUSB Manufacturer:", info.USBManufacturer())
log.Println("\tUSB Product:", info.USBProduct())
log.Println("\tUSB Serial Number:", info.USBSerialNumber())
log.Println("\tBluetooth Address:", info.BluetoothAddress())
port, err := info.Open()
if err != nil {
log.Println("\tOpen:", err)
continue
}
log.Println("\tLocalAddr:", port.LocalAddr().String())
log.Println("\tRemoteAddr:", port.RemoteAddr().String())
if bitrate, err := port.BitRate(); err != nil {
log.Println("\tBit Rate:", err)
} else {
log.Println("\tBit Rate:", bitrate)
}
if databits, err := port.DataBits(); err != nil {
log.Println("\tData Bits:", err)
} else {
log.Println("\tData Bits:", databits)
}
if parity, err := port.Parity(); err != nil {
log.Println("\tParity:", err)
} else {
log.Println("\tParity:", parity)
}
if stopbits, err := port.StopBits(); err != nil {
log.Println("\tStop Bits:", err)
} else {
log.Println("\tStop Bits:", stopbits)
}
if rts, err := port.RTS(); err != nil {
log.Println("\tRTS:", err)
} else {
log.Println("\tRTS:", rts)
}
if cts, err := port.CTS(); err != nil {
log.Println("\tCTS:", err)
} else {
log.Println("\tCTS:", cts)
}
if dtr, err := port.DTR(); err != nil {
log.Println("\tDTR:", err)
} else {
log.Println("\tDTR:", dtr)
}
if dsr, err := port.DSR(); err != nil {
log.Println("\tDSR:", err)
} else {
log.Println("\tDSR:", dsr)
}
if xon, err := port.XonXoff(); err != nil {
log.Println("\tXON/XOFF:", err)
} else {
log.Println("\tXON/XOFF:", xon)
}
/*
if err := port.Apply(&serial.RawOptions); err != nil {
log.Println("\tApply Raw Config:", err)
} else {
log.Println("\tApply Raw Config: ok")
}
*/
if b, err := port.InputWaiting(); err != nil {
log.Println("\tInput Waiting: ", err)
} else {
log.Println("\tInput Waiting: ", b)
}
if b, err := port.OutputWaiting(); err != nil {
log.Println("\tOutput Waiting: ", err)
} else {
log.Println("\tOutput Waiting: ", b)
}
if err := port.Sync(); err != nil {
log.Println("\tSync: ", err)
}
if err := port.Reset(); err != nil {
log.Println("\tReset: ", err)
}
if err := port.ResetInput(); err != nil {
log.Println("\tReset input: ", err)
}
if err := port.ResetOutput(); err != nil {
log.Println("\tReset output: ", err)
}
buf := make([]byte, 1)
if err := port.SetDeadline(time.Now()); err != nil {
log.Println("\tSetDeadline: ", err)
} else {
log.Printf("\tSet deadline")
}
if c, err := port.Read(buf); err != nil {
log.Printf("\tRead immediate %d: %v", c, err)
if err != serial.ErrTimeout {
continue
}
} else {
log.Printf("\tRead immediate %d: %v", c, buf)
}
if c, err := port.Write([]byte{0}); err != nil {
log.Println("\tWrite immediate:", err)
if err != serial.ErrTimeout {
continue
}
} else {
log.Printf("\tWrite immediate %d: %v", c, buf)
}
if err := port.SetDeadline(time.Now().Add(time.Millisecond)); err != nil {
log.Println("\tSetDeadline: ", err)
} else {
log.Printf("\tSet deadline")
}
if c, err := port.Read(buf); err != nil {
log.Printf("\tRead wait %d: %v", c, err)
} else {
log.Printf("\tRead wait %d: %v", c, buf)
}
if err := port.SetDeadline(time.Now().Add(time.Millisecond)); err != nil {
log.Println("\tSetDeadline: ", err)
} else {
log.Printf("\tSet deadline")
}
if c, err := port.Write([]byte{0}); err != nil {
log.Println("\tWrite wait:", err)
} else {
log.Printf("\tWrite wait %d: %v", c, buf)
}
if err := port.SetReadDeadline(time.Time{}); err != nil {
log.Println("\tSetReadDeadline: ", err)
} else {
log.Printf("\tSet read deadline")
}
if err := port.SetWriteDeadline(time.Time{}); err != nil {
log.Println("\tSetWriteDeadline: ", err)
} else {
log.Printf("\tSet write deadline")
}
if c, err := port.Read(buf); err != nil {
log.Printf("\tRead %d: %v", c, err)
} else {
log.Printf("\tRead %d: %v", c, buf)
}
if c, err := port.Write([]byte{0}); err != nil {
log.Println("\tWrite:", err)
} else {
log.Printf("\tWrite %d: %v", c, buf)
}
if err := port.Close(); err != nil {
log.Println(err)
}
}
}

229
vendor/github.com/mikepb/go-serial/macosx.c generated vendored Normal file
View File

@@ -0,0 +1,229 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2013-2014 Martin Ling <martin-libserialport@earth.li>
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef __APPLE__
#include "libserialport.h"
#include "libserialport_internal.h"
SP_PRIV enum sp_return get_port_details(struct sp_port *port)
{
/* Description limited to 127 char,
anything longer would not be user friendly anyway */
char description[128];
int bus, address, vid, pid = -1;
char manufacturer[128], product[128], serial[128];
CFMutableDictionaryRef classes;
io_iterator_t iter;
io_object_t ioport, ioparent;
CFTypeRef cf_property, cf_bus, cf_address, cf_vendor, cf_product;
Boolean result;
char path[PATH_MAX], class[16];
DEBUG("Getting serial port list");
if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue)))
RETURN_FAIL("IOServiceMatching() failed");
if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
&iter) != KERN_SUCCESS)
RETURN_FAIL("IOServiceGetMatchingServices() failed");
DEBUG("Iterating over results");
while ((ioport = IOIteratorNext(iter))) {
if (!(cf_property = IORegistryEntryCreateCFProperty(ioport,
CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0))) {
IOObjectRelease(ioport);
continue;
}
result = CFStringGetCString(cf_property, path, sizeof(path),
kCFStringEncodingASCII);
CFRelease(cf_property);
if (!result || strcmp(path, port->name)) {
IOObjectRelease(ioport);
continue;
}
DEBUG_FMT("Found port %s", path);
IORegistryEntryGetParentEntry(ioport, kIOServicePlane, &ioparent);
if ((cf_property=IORegistryEntrySearchCFProperty(ioparent,kIOServicePlane,
CFSTR("IOProviderClass"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, class, sizeof(class),
kCFStringEncodingASCII) &&
strstr(class, "USB")) {
DEBUG("Found USB class device");
port->transport = SP_TRANSPORT_USB;
}
CFRelease(cf_property);
}
IOObjectRelease(ioparent);
if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Interface Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
(cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Product Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
(cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("Product Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents)) ||
(cf_property = IORegistryEntryCreateCFProperty(ioport,
CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0))) {
if (CFStringGetCString(cf_property, description, sizeof(description),
kCFStringEncodingASCII)) {
DEBUG_FMT("Found description %s", description);
port->description = strdup(description);
}
CFRelease(cf_property);
} else {
DEBUG("No description for this device");
}
cf_bus = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
CFSTR("USBBusNumber"),
kCFAllocatorDefault,
kIORegistryIterateRecursively
| kIORegistryIterateParents);
cf_address = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
CFSTR("USB Address"),
kCFAllocatorDefault,
kIORegistryIterateRecursively
| kIORegistryIterateParents);
if (cf_bus && cf_address &&
CFNumberGetValue(cf_bus , kCFNumberIntType, &bus) &&
CFNumberGetValue(cf_address, kCFNumberIntType, &address)) {
DEBUG_FMT("Found matching USB bus:address %03d:%03d", bus, address);
port->usb_bus = bus;
port->usb_address = address;
}
if (cf_bus ) CFRelease(cf_bus);
if (cf_address) CFRelease(cf_address);
cf_vendor = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
CFSTR("idVendor"),
kCFAllocatorDefault,
kIORegistryIterateRecursively
| kIORegistryIterateParents);
cf_product = IORegistryEntrySearchCFProperty(ioport, kIOServicePlane,
CFSTR("idProduct"),
kCFAllocatorDefault,
kIORegistryIterateRecursively
| kIORegistryIterateParents);
if (cf_vendor && cf_product &&
CFNumberGetValue(cf_vendor , kCFNumberIntType, &vid) &&
CFNumberGetValue(cf_product, kCFNumberIntType, &pid)) {
DEBUG_FMT("Found matching USB vid:pid %04X:%04X", vid, pid);
port->usb_vid = vid;
port->usb_pid = pid;
}
if (cf_vendor ) CFRelease(cf_vendor);
if (cf_product) CFRelease(cf_product);
if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Vendor Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, manufacturer, sizeof(manufacturer),
kCFStringEncodingASCII)) {
DEBUG_FMT("Found manufacturer %s", manufacturer);
port->usb_manufacturer = strdup(manufacturer);
}
CFRelease(cf_property);
}
if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Product Name"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, product, sizeof(product),
kCFStringEncodingASCII)) {
DEBUG_FMT("Found product name %s", product);
port->usb_product = strdup(product);
}
CFRelease(cf_property);
}
if ((cf_property = IORegistryEntrySearchCFProperty(ioport,kIOServicePlane,
CFSTR("USB Serial Number"), kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents))) {
if (CFStringGetCString(cf_property, serial, sizeof(serial),
kCFStringEncodingASCII)) {
DEBUG_FMT("Found serial number %s", serial);
port->usb_serial = strdup(serial);
}
CFRelease(cf_property);
}
IOObjectRelease(ioport);
break;
}
IOObjectRelease(iter);
RETURN_OK();
}
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
CFMutableDictionaryRef classes;
io_iterator_t iter;
char path[PATH_MAX];
io_object_t port;
CFTypeRef cf_path;
Boolean result;
int ret = SP_OK;
DEBUG("Creating matching dictionary");
if (!(classes = IOServiceMatching(kIOSerialBSDServiceValue))) {
SET_FAIL(ret, "IOServiceMatching() failed");
goto out_done;
}
DEBUG("Getting matching services");
if (IOServiceGetMatchingServices(kIOMasterPortDefault, classes,
&iter) != KERN_SUCCESS) {
SET_FAIL(ret, "IOServiceGetMatchingServices() failed");
goto out_done;
}
DEBUG("Iterating over results");
while ((port = IOIteratorNext(iter))) {
cf_path = IORegistryEntryCreateCFProperty(port,
CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
if (cf_path) {
result = CFStringGetCString(cf_path, path, sizeof(path),
kCFStringEncodingASCII);
CFRelease(cf_path);
if (result) {
DEBUG_FMT("Found port %s", path);
if (!(*list = list_append(*list, path))) {
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
IOObjectRelease(port);
goto out;
}
}
}
IOObjectRelease(port);
}
out:
IOObjectRelease(iter);
out_done:
return ret;
}
#endif

1174
vendor/github.com/mikepb/go-serial/serial.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

2320
vendor/github.com/mikepb/go-serial/serialport.c generated vendored Normal file

File diff suppressed because it is too large Load Diff

542
vendor/github.com/mikepb/go-serial/windows.c generated vendored Normal file
View File

@@ -0,0 +1,542 @@
/*
* This file is part of the libserialport project.
*
* Copyright (C) 2013-2014 Martin Ling <martin-libserialport@earth.li>
* Copyright (C) 2014 Aurelien Jacobs <aurel@gnuage.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef _WIN32
#include "libserialport.h"
#include "libserialport_internal.h"
/* USB path is a string of at most 8 decimal numbers < 128 separated by dots */
#define MAX_USB_PATH (8*3 + 7*1 + 1)
static void enumerate_hub(struct sp_port *port, char *hub_name,
char *parent_path);
static char *wc_to_utf8(PWCHAR wc_buffer, ULONG size)
{
WCHAR wc_str[size/sizeof(WCHAR)+1];
char *utf8_str;
/* zero terminate the wide char string */
memcpy(wc_str, wc_buffer, size);
wc_str[sizeof(wc_str)-1] = 0;
/* compute the size of the utf8 converted string */
if (!(size = WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
NULL, 0, NULL, NULL)))
return NULL;
/* allocate utf8 output buffer */
if (!(utf8_str = malloc(size)))
return NULL;
/* actually converted to utf8 */
if (!WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, wc_str, -1,
utf8_str, size, NULL, NULL)) {
free(utf8_str);
return NULL;
}
return utf8_str;
}
static char *get_root_hub_name(HANDLE host_controller)
{
USB_ROOT_HUB_NAME root_hub_name;
PUSB_ROOT_HUB_NAME root_hub_name_wc;
char *root_hub_name_utf8;
ULONG size = 0;
/* compute the size of the root hub name string */
if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME, 0, 0,
&root_hub_name, sizeof(root_hub_name), &size, NULL))
return NULL;
/* allocate wide char root hub name string */
size = root_hub_name.ActualLength;
if (!(root_hub_name_wc = malloc(size)))
return NULL;
/* actually get the root hub name string */
if (!DeviceIoControl(host_controller, IOCTL_USB_GET_ROOT_HUB_NAME,
NULL, 0, root_hub_name_wc, size, &size, NULL)) {
free(root_hub_name_wc);
return NULL;
}
/* convert the root hub name string to utf8 */
root_hub_name_utf8 = wc_to_utf8(root_hub_name_wc->RootHubName, size);
free(root_hub_name_wc);
return root_hub_name_utf8;
}
static char *get_external_hub_name(HANDLE hub, ULONG connection_index)
{
USB_NODE_CONNECTION_NAME ext_hub_name;
PUSB_NODE_CONNECTION_NAME ext_hub_name_wc;
char *ext_hub_name_utf8;
ULONG size;
/* compute the size of the external hub name string */
ext_hub_name.ConnectionIndex = connection_index;
if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
&ext_hub_name, sizeof(ext_hub_name),
&ext_hub_name, sizeof(ext_hub_name), &size, NULL))
return NULL;
/* allocate wide char external hub name string */
size = ext_hub_name.ActualLength;
if (size <= sizeof(ext_hub_name)
|| !(ext_hub_name_wc = malloc(size)))
return NULL;
/* get the name of the external hub attached to the specified port */
ext_hub_name_wc->ConnectionIndex = connection_index;
if (!DeviceIoControl(hub, IOCTL_USB_GET_NODE_CONNECTION_NAME,
ext_hub_name_wc, size,
ext_hub_name_wc, size, &size, NULL)) {
free(ext_hub_name_wc);
return NULL;
}
/* convert the external hub name string to utf8 */
ext_hub_name_utf8 = wc_to_utf8(ext_hub_name_wc->NodeName, size);
free(ext_hub_name_wc);
return ext_hub_name_utf8;
}
static char *get_string_descriptor(HANDLE hub_device, ULONG connection_index,
UCHAR descriptor_index)
{
char desc_req_buf[sizeof(USB_DESCRIPTOR_REQUEST) +
MAXIMUM_USB_STRING_LENGTH] = { 0 };
PUSB_DESCRIPTOR_REQUEST desc_req = (void *) desc_req_buf;
PUSB_STRING_DESCRIPTOR desc = (void *) (desc_req + 1);
ULONG size = sizeof(desc_req_buf);
desc_req->ConnectionIndex = connection_index;
desc_req->SetupPacket.wValue = (USB_STRING_DESCRIPTOR_TYPE << 8)
| descriptor_index;
desc_req->SetupPacket.wIndex = 0;
desc_req->SetupPacket.wLength = size - sizeof(*desc_req);
if (!DeviceIoControl(hub_device,
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION,
desc_req, size, desc_req, size, &size, NULL)
|| size < 2
|| desc->bDescriptorType != USB_STRING_DESCRIPTOR_TYPE
|| desc->bLength != size - sizeof(*desc_req)
|| desc->bLength % 2)
return NULL;
return wc_to_utf8(desc->bString, desc->bLength);
}
static void enumerate_hub_ports(struct sp_port *port, HANDLE hub_device,
ULONG nb_ports, char *parent_path)
{
char path[MAX_USB_PATH];
ULONG index = 0;
for (index = 1; index <= nb_ports; index++) {
PUSB_NODE_CONNECTION_INFORMATION_EX connection_info_ex;
ULONG size = sizeof(*connection_info_ex) + 30*sizeof(USB_PIPE_INFO);
if (!(connection_info_ex = malloc(size)))
break;
connection_info_ex->ConnectionIndex = index;
if (!DeviceIoControl(hub_device,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX,
connection_info_ex, size,
connection_info_ex, size, &size, NULL)) {
/* try to get CONNECTION_INFORMATION if CONNECTION_INFORMATION_EX
did not work */
PUSB_NODE_CONNECTION_INFORMATION connection_info;
size = sizeof(*connection_info) + 30*sizeof(USB_PIPE_INFO);
if (!(connection_info = malloc(size))) {
free(connection_info_ex);
continue;
}
connection_info->ConnectionIndex = index;
if (!DeviceIoControl(hub_device,
IOCTL_USB_GET_NODE_CONNECTION_INFORMATION,
connection_info, size,
connection_info, size, &size, NULL)) {
free(connection_info);
free(connection_info_ex);
continue;
}
connection_info_ex->ConnectionIndex = connection_info->ConnectionIndex;
connection_info_ex->DeviceDescriptor = connection_info->DeviceDescriptor;
connection_info_ex->DeviceIsHub = connection_info->DeviceIsHub;
connection_info_ex->DeviceAddress = connection_info->DeviceAddress;
free(connection_info);
}
if (connection_info_ex->DeviceIsHub) {
/* recursively enumerate external hub */
PCHAR ext_hub_name;
if ((ext_hub_name = get_external_hub_name(hub_device, index))) {
snprintf(path, sizeof(path), "%s%ld.",
parent_path, connection_info_ex->ConnectionIndex);
enumerate_hub(port, ext_hub_name, path);
}
free(connection_info_ex);
} else {
snprintf(path, sizeof(path), "%s%ld",
parent_path, connection_info_ex->ConnectionIndex);
/* check if this device is the one we search for */
if (strcmp(path, port->usb_path)) {
free(connection_info_ex);
continue;
}
/* finally grab detailed informations regarding the device */
port->usb_address = connection_info_ex->DeviceAddress + 1;
port->usb_vid = connection_info_ex->DeviceDescriptor.idVendor;
port->usb_pid = connection_info_ex->DeviceDescriptor.idProduct;
if (connection_info_ex->DeviceDescriptor.iManufacturer)
port->usb_manufacturer = get_string_descriptor(hub_device,index,
connection_info_ex->DeviceDescriptor.iManufacturer);
if (connection_info_ex->DeviceDescriptor.iProduct)
port->usb_product = get_string_descriptor(hub_device, index,
connection_info_ex->DeviceDescriptor.iProduct);
if (connection_info_ex->DeviceDescriptor.iSerialNumber)
port->usb_serial = get_string_descriptor(hub_device, index,
connection_info_ex->DeviceDescriptor.iSerialNumber);
free(connection_info_ex);
break;
}
}
}
static void enumerate_hub(struct sp_port *port, char *hub_name,
char *parent_path)
{
USB_NODE_INFORMATION hub_info;
HANDLE hub_device;
ULONG size = sizeof(hub_info);
char *device_name;
/* open the hub with its full name */
if (!(device_name = malloc(strlen("\\\\.\\") + strlen(hub_name) + 1)))
return;
strcpy(device_name, "\\\\.\\");
strcat(device_name, hub_name);
hub_device = CreateFile(device_name, GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
free(device_name);
if (hub_device == INVALID_HANDLE_VALUE)
return;
/* get the number of ports of the hub */
if (DeviceIoControl(hub_device, IOCTL_USB_GET_NODE_INFORMATION,
&hub_info, size, &hub_info, size, &size, NULL))
/* enumerate the ports of the hub */
enumerate_hub_ports(port, hub_device,
hub_info.u.HubInformation.HubDescriptor.bNumberOfPorts, parent_path);
CloseHandle(hub_device);
}
static void enumerate_host_controller(struct sp_port *port,
HANDLE host_controller_device)
{
char *root_hub_name;
if ((root_hub_name = get_root_hub_name(host_controller_device))) {
enumerate_hub(port, root_hub_name, "");
free(root_hub_name);
}
}
static void get_usb_details(struct sp_port *port, DEVINST dev_inst_match)
{
HDEVINFO device_info;
SP_DEVINFO_DATA device_info_data;
ULONG i, size = 0;
device_info = SetupDiGetClassDevs(&GUID_CLASS_USB_HOST_CONTROLLER,NULL,NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
device_info_data.cbSize = sizeof(device_info_data);
for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
SP_DEVICE_INTERFACE_DATA device_interface_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA device_detail_data;
DEVINST dev_inst = dev_inst_match;
HANDLE host_controller_device;
device_interface_data.cbSize = sizeof(device_interface_data);
if (!SetupDiEnumDeviceInterfaces(device_info, 0,
&GUID_CLASS_USB_HOST_CONTROLLER,
i, &device_interface_data))
continue;
if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
NULL, 0, &size, NULL)
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER)
continue;
if (!(device_detail_data = malloc(size)))
continue;
device_detail_data->cbSize = sizeof(*device_detail_data);
if (!SetupDiGetDeviceInterfaceDetail(device_info,&device_interface_data,
device_detail_data, size, &size,
NULL)) {
free(device_detail_data);
continue;
}
while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS
&& dev_inst != device_info_data.DevInst) { }
if (dev_inst != device_info_data.DevInst) {
free(device_detail_data);
continue;
}
port->usb_bus = i + 1;
host_controller_device = CreateFile(device_detail_data->DevicePath,
GENERIC_WRITE, FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);
if (host_controller_device != INVALID_HANDLE_VALUE) {
enumerate_host_controller(port, host_controller_device);
CloseHandle(host_controller_device);
}
free(device_detail_data);
}
SetupDiDestroyDeviceInfoList(device_info);
return;
}
SP_PRIV enum sp_return get_port_details(struct sp_port *port)
{
/* Description limited to 127 char,
anything longer would not be user friendly anyway */
char description[128];
SP_DEVINFO_DATA device_info_data = { .cbSize = sizeof(device_info_data) };
HDEVINFO device_info;
int i;
device_info = SetupDiGetClassDevs(NULL, 0, 0,
DIGCF_PRESENT | DIGCF_ALLCLASSES);
if (device_info == INVALID_HANDLE_VALUE)
RETURN_FAIL("SetupDiGetClassDevs() failed");
for (i=0; SetupDiEnumDeviceInfo(device_info, i, &device_info_data); i++) {
HKEY device_key;
DEVINST dev_inst;
char value[8], class[16];
DWORD size, type;
CONFIGRET cr;
/* check if this is the device we are looking for */
device_key = SetupDiOpenDevRegKey(device_info, &device_info_data,
DICS_FLAG_GLOBAL, 0,
DIREG_DEV, KEY_QUERY_VALUE);
if (device_key == INVALID_HANDLE_VALUE)
continue;
size = sizeof(value);
if (RegQueryValueExA(device_key, "PortName", NULL, &type, (LPBYTE)value,
&size) != ERROR_SUCCESS || type != REG_SZ) {
RegCloseKey(device_key);
continue;
}
RegCloseKey(device_key);
value[sizeof(value)-1] = 0;
if (strcmp(value, port->name))
continue;
/* check port transport type */
dev_inst = device_info_data.DevInst;
size = sizeof(class);
cr = CR_FAILURE;
while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS &&
(cr = CM_Get_DevNode_Registry_PropertyA(dev_inst,
CM_DRP_CLASS, 0, class, &size, 0)) != CR_SUCCESS) { }
if (cr == CR_SUCCESS) {
if (!strcmp(class, "USB"))
port->transport = SP_TRANSPORT_USB;
}
/* get port description (friendly name) */
dev_inst = device_info_data.DevInst;
size = sizeof(description);
while ((cr = CM_Get_DevNode_Registry_PropertyA(dev_inst,
CM_DRP_FRIENDLYNAME, 0, description, &size, 0)) != CR_SUCCESS
&& CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS) { }
if (cr == CR_SUCCESS)
port->description = strdup(description);
/* get more informations for USB connected ports */
if (port->transport == SP_TRANSPORT_USB) {
char usb_path[MAX_USB_PATH] = "", tmp[MAX_USB_PATH];
char device_id[MAX_DEVICE_ID_LEN];
/* recurse over parents to build the USB device path */
dev_inst = device_info_data.DevInst;
do {
/* verify that this layer of the tree is USB related */
if (CM_Get_Device_IDA(dev_inst, device_id,
sizeof(device_id), 0) != CR_SUCCESS
|| strncmp(device_id, "USB\\", 4))
continue;
/* discard one layer for composite devices */
char compat_ids[512], *p = compat_ids;
size = sizeof(compat_ids);
if (CM_Get_DevNode_Registry_PropertyA(dev_inst,
CM_DRP_COMPATIBLEIDS, 0,
&compat_ids,
&size, 0) == CR_SUCCESS) {
while (*p) {
if (!strncmp(p, "USB\\COMPOSITE", 13))
break;
p += strlen(p) + 1;
}
if (*p)
continue;
}
/* stop the recursion when reaching the USB root */
if (!strncmp(device_id, "USB\\ROOT", 8))
break;
/* prepend the address of current USB layer to the USB path */
DWORD address;
size = sizeof(address);
if (CM_Get_DevNode_Registry_PropertyA(dev_inst, CM_DRP_ADDRESS,
0, &address, &size, 0) == CR_SUCCESS) {
strcpy(tmp, usb_path);
snprintf(usb_path, sizeof(usb_path), "%d%s%s",
(int)address, *tmp ? "." : "", tmp);
}
} while (CM_Get_Parent(&dev_inst, dev_inst, 0) == CR_SUCCESS);
port->usb_path = strdup(usb_path);
/* wake up the USB device to be able to read string descriptor */
char *escaped_port_name;
HANDLE handle;
if (!(escaped_port_name = malloc(strlen(port->name) + 5)))
RETURN_ERROR(SP_ERR_MEM, "Escaped port name malloc failed");
sprintf(escaped_port_name, "\\\\.\\%s", port->name);
handle = CreateFile(escaped_port_name, GENERIC_READ, 0, 0,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, 0);
free(escaped_port_name);
CloseHandle(handle);
/* retrieve USB device details from the device descriptor */
get_usb_details(port, device_info_data.DevInst);
}
break;
}
SetupDiDestroyDeviceInfoList(device_info);
RETURN_OK();
}
SP_PRIV enum sp_return list_ports(struct sp_port ***list)
{
HKEY key;
TCHAR *value, *data;
DWORD max_value_len, max_data_size, max_data_len;
DWORD value_len, data_size, data_len;
DWORD type, index = 0;
char *name;
int name_len;
int ret = SP_OK;
DEBUG("Opening registry key");
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("HARDWARE\\DEVICEMAP\\SERIALCOMM"),
0, KEY_QUERY_VALUE, &key) != ERROR_SUCCESS) {
SET_FAIL(ret, "RegOpenKeyEx() failed");
goto out_done;
}
DEBUG("Querying registry key value and data sizes");
if (RegQueryInfoKey(key, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
&max_value_len, &max_data_size, NULL, NULL) != ERROR_SUCCESS) {
SET_FAIL(ret, "RegQueryInfoKey() failed");
goto out_close;
}
max_data_len = max_data_size / sizeof(TCHAR);
if (!(value = malloc((max_value_len + 1) * sizeof(TCHAR)))) {
SET_ERROR(ret, SP_ERR_MEM, "registry value malloc failed");
goto out_close;
}
if (!(data = malloc((max_data_len + 1) * sizeof(TCHAR)))) {
SET_ERROR(ret, SP_ERR_MEM, "registry data malloc failed");
goto out_free_value;
}
DEBUG("Iterating over values");
while (
value_len = max_value_len + 1,
data_size = max_data_size,
RegEnumValue(key, index, value, &value_len,
NULL, &type, (LPBYTE)data, &data_size) == ERROR_SUCCESS)
{
if (type == REG_SZ) {
data_len = data_size / sizeof(TCHAR);
data[data_len] = '\0';
#ifdef UNICODE
name_len = WideCharToMultiByte(CP_ACP, 0, data, -1, NULL, 0, NULL, NULL);
#else
name_len = data_len + 1;
#endif
if (!(name = malloc(name_len))) {
SET_ERROR(ret, SP_ERR_MEM, "registry port name malloc failed");
goto out;
}
#ifdef UNICODE
WideCharToMultiByte(CP_ACP, 0, data, -1, name, name_len, NULL, NULL);
#else
strcpy(name, data);
#endif
DEBUG_FMT("Found port %s", name);
if (!(*list = list_append(*list, name))) {
SET_ERROR(ret, SP_ERR_MEM, "list append failed");
free(name);
goto out;
}
free(name);
}
index++;
}
out:
free(data);
out_free_value:
free(value);
out_close:
RegCloseKey(key);
out_done:
return ret;
}
#endif