libaltos: Mac OS X cannot use 'poll(2)' on serial lines.
[fw/altos] / ao-tools / libaltos / libaltos.c
index 00fb2125443bc452b9807f8f106d81b726dd30b9..65cd6c1a89bff2b2f6d3c7c0ca48388d814db0e3 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#define BUILD_DLL
 #include "libaltos.h"
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
-static int
-match_dev(char *product, int serial, struct altos_device *device)
+#define USE_POLL
+
+PUBLIC int
+altos_init(void)
 {
-       struct altos_list       *list;
-       int                     i;
+       return LIBALTOS_SUCCESS;
+}
 
-       list = altos_list_start();
-       if (!list)
-               return 0;
-       while ((i = altos_list_next(list, device)) != 0) {
-               if (product && strncmp (product, device->product, strlen(product)) != 0)
-                       continue;
-               if (serial && serial != device->serial)
-                       continue;
-               break;
-       }
-       altos_list_finish(list);
-       return i;
+PUBLIC void
+altos_fini(void)
+{
 }
 
 #ifdef DARWIN
+
+#undef USE_POLL
+
 /* Mac OS X don't have strndup even if _GNU_SOURCE is defined */
 static char *
 altos_strndup (const char *s, size_t n)
@@ -60,48 +57,9 @@ altos_strndup (const char *s, size_t n)
 #define altos_strndup strndup
 #endif
 
-int
-altos_find_by_arg(char *arg, char *default_product, struct altos_device *device)
-{
-       char    *product;
-       int     serial;
-       char    *end;
-       char    *colon;
-       int     ret;
-
-       if (arg)
-       {
-               /* check for <serial> */
-               serial = strtol(arg, &end, 0);
-               if (end != arg) {
-                       if (*end != '\0')
-                               return 0;
-                       product = NULL;
-               } else {
-                       /* check for <product>:<serial> */
-                       colon = strchr(arg, ':');
-                       if (colon) {
-                               product = altos_strndup(arg, colon - arg);
-                               serial = strtol(colon + 1, &end, 0);
-                               if (*end != '\0')
-                                       return 0;
-                       } else {
-                               product = arg;
-                               serial = 0;
-                       }
-               }
-       } else {
-               product = NULL;
-               serial = 0;
-       }
-       if (!product && default_product)
-               ret = match_dev(default_product, serial, device);
-       if (!ret)
-               ret = match_dev(product, serial, device);
-       if (product && product != arg)
-               free(product);
-       return ret;
-}
+/*
+ * Scan for Altus Metrum devices by looking through /sys
+ */
 
 #ifdef LINUX
 
@@ -216,7 +174,7 @@ struct altos_usbdev {
        char    *sys;
        char    *tty;
        char    *manufacturer;
-       char    *product;
+       char    *product_name;
        int     serial; /* AltOS always uses simple integer serial numbers */
        int     idProduct;
        int     idVendor;
@@ -286,7 +244,7 @@ usb_scan_device(char *sys)
                return NULL;
        usbdev->sys = strdup(sys);
        usbdev->manufacturer = load_string(sys, "manufacturer");
-       usbdev->product = load_string(sys, "product");
+       usbdev->product_name = load_string(sys, "product");
        usbdev->serial = load_dec(sys, "serial");
        usbdev->idProduct = load_hex(sys, "idProduct");
        usbdev->idVendor = load_hex(sys, "idVendor");
@@ -299,7 +257,7 @@ usbdev_free(struct altos_usbdev *usbdev)
 {
        free(usbdev->sys);
        free(usbdev->manufacturer);
-       free(usbdev->product);
+       free(usbdev->product_name);
        /* this can get used as a return value */
        if (usbdev->tty)
                free(usbdev->tty);
@@ -332,17 +290,6 @@ struct altos_list {
        int                     ndev;
 };
 
-int
-altos_init(void)
-{
-       return 1;
-}
-
-void
-altos_fini(void)
-{
-}
-
 struct altos_list *
 altos_list_start(void)
 {
@@ -366,7 +313,7 @@ altos_list_start(void)
                dir = cc_fullname(USB_DEVICES, ents[e]->d_name);
                dev = usb_scan_device(dir);
                free(dir);
-               if (dev->idVendor == 0xfffe && dev->tty) {
+               if (USB_IS_ALTUSMETRUM(dev->idVendor, dev->idProduct)) {
                        if (devs->dev)
                                devs->dev = realloc(devs->dev,
                                                    devs->ndev + 1 * sizeof (struct usbdev *));
@@ -387,7 +334,9 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
        if (list->current >= list->ndev)
                return 0;
        dev = list->dev[list->current];
-       strcpy(device->product, dev->product);
+       strcpy(device->name, dev->product_name);
+       device->vendor = dev->idVendor;
+       device->product = dev->idProduct;
        strcpy(device->path, dev->tty);
        device->serial = dev->serial;
        list->current++;
@@ -447,15 +396,25 @@ get_string(io_object_t object, CFStringRef entry, char *result, int result_len)
        return 0;
 }
 
-int
-altos_init(void)
-{
-       return 1;
-}
-
-void
-altos_fini(void)
+static int
+get_number(io_object_t object, CFStringRef entry, int *result)
 {
+       CFTypeRef entry_as_number;
+       Boolean got_number;
+       
+       entry_as_number = IORegistryEntrySearchCFProperty (object,
+                                                          kIOServicePlane,
+                                                          entry,
+                                                          kCFAllocatorDefault,
+                                                          kIORegistryIterateRecursively);
+       if (entry_as_number) {
+               got_number = CFNumberGetValue(entry_as_number,
+                                             kCFNumberIntType,
+                                             result);
+               if (got_number)
+                       return 1;
+       }
+       return 0;
 }
 
 struct altos_list *
@@ -463,19 +422,14 @@ altos_list_start(void)
 {
        struct altos_list *list = calloc (sizeof (struct altos_list), 1);
        CFMutableDictionaryRef matching_dictionary = IOServiceMatching("IOUSBDevice");
-       UInt32 vendor = 0xfffe, product = 0x000a;
-       CFNumberRef vendor_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &vendor);
-       CFNumberRef product_ref = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &product);
        io_iterator_t tdIterator;
        io_object_t tdObject;
-  
-       CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBVendorID), vendor_ref);
-       CFDictionaryAddValue(matching_dictionary, CFSTR(kUSBProductID), product_ref);
+       kern_return_t ret;
+       int i;
 
-       IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
-  
-       CFRelease(vendor_ref);
-       CFRelease(product_ref);
+       ret = IOServiceGetMatchingServices(kIOMasterPortDefault, matching_dictionary, &list->iterator);
+       if (ret != kIOReturnSuccess)
+               return NULL;
        return list;
 }
 
@@ -490,8 +444,15 @@ altos_list_next(struct altos_list *list, struct altos_device *device)
                if (!object)
                        return 0;
   
+               if (!get_number (object, CFSTR(kUSBVendorID), &device->vendor) ||
+                   !get_number (object, CFSTR(kUSBProductID), &device->product))
+                       continue;
+               if (device->vendor != 0xfffe)
+                       continue;
+               if (device->product < 0x000a || 0x0013 < device->product)
+                       continue;
                if (get_string (object, CFSTR("IOCalloutDevice"), device->path, sizeof (device->path)) &&
-                   get_string (object, CFSTR("USB Product Name"), device->product, sizeof (device->product)) &&
+                   get_string (object, CFSTR("USB Product Name"), device->name, sizeof (device->name)) &&
                    get_string (object, CFSTR("USB Serial Number"), serial_string, sizeof (serial_string))) {
                        device->serial = atoi(serial_string);
                        return 1;
@@ -520,6 +481,11 @@ altos_list_finish(struct altos_list *list)
 
 struct altos_file {
        int                             fd;
+#ifdef USE_POLL
+       int                             pipe[2];
+#else
+       int                             out_fd;
+#endif
        unsigned char                   out_data[USB_BUF_SIZE];
        int                             out_used;
        unsigned char                   in_data[USB_BUF_SIZE];
@@ -537,47 +503,106 @@ altos_open(struct altos_device *device)
        if (!file)
                return NULL;
 
+       printf("open %s\n", device->path);
        file->fd = open(device->path, O_RDWR | O_NOCTTY);
+       printf("opened %d\n", file->fd);
        if (file->fd < 0) {
                perror(device->path);
                free(file);
                return NULL;
        }
+#ifdef USE_POLL
+       pipe(file->pipe);
+#else
+       file->out_fd = open(device->path, O_RDWR | O_NOCTTY);
+       if (file->out_fd < 0) {
+               perror(device->path);
+               close(file->fd);
+               free(file);
+               return NULL;
+       }
+#endif
        ret = tcgetattr(file->fd, &term);
        if (ret < 0) {
                perror("tcgetattr");
                close(file->fd);
+#ifndef USE_POLL
+               close(file->out_fd);
+#endif
                free(file);
                return NULL;
        }
        cfmakeraw(&term);
+#ifdef USE_POLL
+       term.c_cc[VMIN] = 1;
+       term.c_cc[VTIME] = 0;
+#else
        term.c_cc[VMIN] = 0;
        term.c_cc[VTIME] = 1;
+#endif
        ret = tcsetattr(file->fd, TCSAFLUSH, &term);
        if (ret < 0) {
                perror("tcsetattr");
                close(file->fd);
+#ifndef USE_POLL
+               close(file->out_fd);
+#endif
                free(file);
                return NULL;
        }
+       printf("running %d\n", file->fd);
        return file;
 }
 
 void
 altos_close(struct altos_file *file)
 {
-       close(file->fd);
-       file->fd = -1;
+       if (file->fd != -1) {
+               int     fd = file->fd;
+               file->fd = -1;
+#ifdef USE_POLL
+               write(file->pipe[1], "\r", 1);
+#else
+               close(file->out_fd);
+               file->out_fd = -1;
+#endif
+               printf("close %d\n", fd);
+               close(fd);
+       }
 }
 
 void
 altos_free(struct altos_file *file)
 {
-       if (file->fd != -1)
-               close(file->fd);
+       altos_close(file);
        free(file);
 }
 
+int
+altos_flush(struct altos_file *file)
+{
+       while (file->out_used) {
+               int     ret;
+
+               if (file->fd < 0)
+                       return -EBADF;
+               printf("write %d\n", file->out_used);
+#ifdef USE_POLL
+               ret = write (file->fd, file->out_data, file->out_used);
+#else
+               ret = write (file->out_fd, file->out_data, file->out_used);
+#endif
+               if (ret < 0)
+                       return -errno;
+               if (ret) {
+                       memmove(file->out_data, file->out_data + ret,
+                               file->out_used - ret);
+                       file->out_used -= ret;
+               }
+       }
+       return 0;
+}
+
 int
 altos_putchar(struct altos_file *file, char c)
 {
@@ -585,191 +610,332 @@ altos_putchar(struct altos_file *file, char c)
 
        if (file->out_used == USB_BUF_SIZE) {
                ret = altos_flush(file);
-               if (ret)
+               if (ret) {
                        return ret;
+               }
        }
        file->out_data[file->out_used++] = c;
+       ret = 0;
        if (file->out_used == USB_BUF_SIZE)
-               return altos_flush(file);
+               ret = altos_flush(file);
        return 0;
 }
 
+#ifdef USE_POLL
+#include <poll.h>
+#endif
+
 int
-altos_flush(struct altos_file *file)
+altos_fill(struct altos_file *file, int timeout)
 {
-       while (file->out_used) {
-               int     ret;
+       int             ret;
+#ifdef USE_POLL
+       struct pollfd   fd[2];
+#endif
 
+       if (timeout == 0)
+               timeout = -1;
+       while (file->in_read == file->in_used) {
                if (file->fd < 0)
-                       return -EBADF;
-               ret = write (file->fd, file->out_data, file->out_used);
-               if (ret < 0)
-                       return -errno;
-               if (ret) {
-                       memmove(file->out_data, file->out_data + ret,
-                               file->out_used - ret);
-                       file->out_used -= ret;
+                       return LIBALTOS_ERROR;
+#ifdef USE_POLL
+               fd[0].fd = file->fd;
+               fd[0].events = POLLIN;
+               fd[1].fd = file->pipe[0];
+               fd[1].events = POLLIN;
+               ret = poll(fd, 2, timeout);
+               if (ret < 0) {
+                       perror("altos_getchar");
+                       return LIBALTOS_ERROR;
+               }
+               if (ret == 0)
+                       return LIBALTOS_TIMEOUT;
+               if (fd[0].revents & POLLIN)
+#endif
+               {
+                       ret = read(file->fd, file->in_data, USB_BUF_SIZE);
+                       if (ret)
+                               printf("read %d\n", ret);
+                       if (ret < 0) {
+                               perror("altos_getchar");
+                               return LIBALTOS_ERROR;
+                       }
+                       file->in_read = 0;
+                       file->in_used = ret;
+#ifndef USE_POLL
+                       if (ret == 0 && timeout > 0)
+                               return LIBALTOS_TIMEOUT;
+#endif
                }
        }
+       return 0;
 }
 
 int
 altos_getchar(struct altos_file *file, int timeout)
 {
+       int     ret;
        while (file->in_read == file->in_used) {
-               int     ret;
-
-               altos_flush(file);
                if (file->fd < 0)
-                       return -EBADF;
-               ret = read(file->fd, file->in_data, USB_BUF_SIZE);
-               if (ret < 0)
-                       return -errno;
-               file->in_read = 0;
-               file->in_used = ret;
+                       return LIBALTOS_ERROR;
+               ret = altos_fill(file, timeout);
+               if (ret)
+                       return ret;
        }
        return file->in_data[file->in_read++];
 }
 
 #endif /* POSIX_TTY */
 
-#ifdef USE_LIBUSB
-#include <libusb.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
+#ifdef WINDOWS
 
-libusb_context *usb_context;
+#include <windows.h>
+#include <setupapi.h>
 
-int altos_init(void)
-{
-       int     ret;
-       ret = libusb_init(&usb_context);
-       if (ret)
-               return ret;
-       libusb_set_debug(usb_context, 3);
-       return 0;
-}
+struct altos_list {
+       HDEVINFO        dev_info;
+       int             index;
+};
 
-void altos_fini(void)
-{
-       libusb_exit(usb_context);
-       usb_context = NULL;
-}
+#define USB_BUF_SIZE   64
 
-static libusb_device **list;
-static ssize_t num, current;
+struct altos_file {
+       HANDLE                          handle;
+       unsigned char                   out_data[USB_BUF_SIZE];
+       int                             out_used;
+       unsigned char                   in_data[USB_BUF_SIZE];
+       int                             in_used;
+       int                             in_read;
+};
 
-int altos_list_start(void)
+
+PUBLIC struct altos_list *
+altos_list_start(void)
 {
-       if (list)
-               altos_list_finish();
-       current = 0;
-       num = libusb_get_device_list(usb_context, &list);
-       if (num == 0) {
-               current = num = 0;
-               list = NULL;
-               return 0;
+       struct altos_list       *list = calloc(1, sizeof (struct altos_list));
+
+       if (!list)
+               return NULL;
+       list->dev_info = SetupDiGetClassDevs(NULL, "USB", NULL,
+                                            DIGCF_ALLCLASSES|DIGCF_PRESENT);
+       if (list->dev_info == INVALID_HANDLE_VALUE) {
+               printf("SetupDiGetClassDevs failed %d\n", GetLastError());
+               free(list);
+               return NULL;
        }
-       return 1;
+       list->index = 0;
+       return list;
 }
 
-int altos_list_next(struct altos_device *device)
-{
-       while (current < num) {
-               struct libusb_device_descriptor descriptor;
-               libusb_device *usb_device = list[current++];
-
-               if (libusb_get_device_descriptor(usb_device, &descriptor) == 0) {
-                       if (descriptor.idVendor == 0xfffe)
-                       {
-                               libusb_device_handle    *handle;
-                               if (libusb_open(usb_device, &handle) == 0) {
-                                       char    serial_number[256];
-                                       libusb_get_string_descriptor_ascii(handle, descriptor.iProduct,
-                                                                          device->product,
-                                                                          sizeof(device->product));
-                                       libusb_get_string_descriptor_ascii(handle, descriptor.iSerialNumber,
-                                                                          serial_number,
-                                                                          sizeof (serial_number));
-                                       libusb_close(handle);
-                                       device->serial = atoi(serial_number);
-                                       device->device = usb_device;
-                                       return 1;
-                               }
-                       }
+PUBLIC int
+altos_list_next(struct altos_list *list, struct altos_device *device)
+{
+       SP_DEVINFO_DATA dev_info_data;
+       char            port[128];
+       DWORD           port_len;
+       char            location[256];
+       char            symbolic[256];
+       DWORD           symbolic_len;
+       HKEY            dev_key;
+       int             vid, pid;
+       int             serial;
+       HRESULT         result;
+       DWORD           location_type;
+       DWORD           location_len;
+
+       dev_info_data.cbSize = sizeof (SP_DEVINFO_DATA);
+       while(SetupDiEnumDeviceInfo(list->dev_info, list->index,
+                                   &dev_info_data))
+       {
+               list->index++;
+
+               dev_key = SetupDiOpenDevRegKey(list->dev_info, &dev_info_data,
+                                              DICS_FLAG_GLOBAL, 0, DIREG_DEV,
+                                              KEY_READ);
+               if (dev_key == INVALID_HANDLE_VALUE) {
+                       printf("cannot open device registry key\n");
+                       continue;
+               }
+
+               /* Fetch symbolic name for this device and parse out
+                * the vid/pid/serial info */
+               symbolic_len = sizeof(symbolic);
+               result = RegQueryValueEx(dev_key, "SymbolicName", NULL, NULL,
+                                        symbolic, &symbolic_len);
+               if (result != 0) {
+                       printf("cannot find SymbolicName value\n");
+                       RegCloseKey(dev_key);
+                       continue;
                }
+               vid = pid = serial = 0;
+               sscanf(symbolic + sizeof("\\??\\USB#VID_") - 1,
+                      "%04X", &vid);
+               sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_") - 1,
+                      "%04X", &pid);
+               sscanf(symbolic + sizeof("\\??\\USB#VID_XXXX&PID_XXXX#") - 1,
+                      "%d", &serial);
+               if (!USB_IS_ALTUSMETRUM(vid, pid)) {
+                       printf("Not Altus Metrum symbolic name: %s\n",
+                              symbolic);
+                       RegCloseKey(dev_key);
+                       continue;
+               }
+
+               /* Fetch the com port name */
+               port_len = sizeof (port);
+               result = RegQueryValueEx(dev_key, "PortName", NULL, NULL,
+                                        port, &port_len);
+               RegCloseKey(dev_key);
+               if (result != 0) {
+                       printf("failed to get PortName\n");
+                       continue;
+               }
+
+               /* Fetch the 'location information' which is the device name,
+                * at least on XP */
+               location_len = sizeof (location);
+               if(!SetupDiGetDeviceRegistryProperty(list->dev_info,
+                                                    &dev_info_data,
+                                                    SPDRP_LOCATION_INFORMATION,
+                                                    &location_type,
+                                                    (BYTE *)location,
+                                                    sizeof(location),
+                                                    &location_len))
+               {
+                       printf("Failed to get location\n");
+                       continue;
+               }
+               device->vendor = vid;
+               device->product = pid;
+               device->serial = serial;
+
+               if (strcasestr(location, "tele"))
+                       strcpy(device->name, location);
+               else
+                       strcpy(device->name, "");
+
+               strcpy(device->path, port);
+               printf ("product: %04x:%04x (%s)  path: %s serial %d\n",
+                       device->vendor, device->product, device->name,
+                       device->path, device->serial);
+               return 1;
        }
+       result = GetLastError();
+       if (result != ERROR_NO_MORE_ITEMS)
+               printf ("SetupDiEnumDeviceInfo failed error %d\n", result);
        return 0;
 }
 
-void altos_list_finish(void)
+PUBLIC void
+altos_list_finish(struct altos_list *list)
 {
-       if (list) {
-               libusb_free_device_list(list, 1);
-               list = NULL;
+       SetupDiDestroyDeviceInfoList(list->dev_info);
+       free(list);
+}
+
+static int
+altos_fill(struct altos_file *file, int timeout)
+{
+       DWORD   result;
+       DWORD   got;
+       COMMTIMEOUTS timeouts;
+
+       if (file->in_read < file->in_used)
+               return LIBALTOS_SUCCESS;
+       file->in_read = file->in_used = 0;
+
+       if (timeout) {
+               timeouts.ReadIntervalTimeout = MAXDWORD;
+               timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
+               timeouts.ReadTotalTimeoutConstant = timeout;
+       } else {
+               timeouts.ReadIntervalTimeout = 0;
+               timeouts.ReadTotalTimeoutMultiplier = 0;
+               timeouts.ReadTotalTimeoutConstant = 0;
+       }
+       timeouts.WriteTotalTimeoutMultiplier = 0;
+       timeouts.WriteTotalTimeoutConstant = 0;
+
+       if (!SetCommTimeouts(file->handle, &timeouts)) {
+               printf("SetCommTimeouts failed %d\n", GetLastError());
        }
+
+       if (!ReadFile(file->handle, file->in_data, USB_BUF_SIZE, &got, NULL)) {
+               result = GetLastError();
+               printf ("read failed %d\n", result);
+               return LIBALTOS_ERROR;
+               got = 0;
+       }
+       if (got)
+               return LIBALTOS_SUCCESS;
+       return LIBALTOS_TIMEOUT;
 }
 
-#define USB_BUF_SIZE   64
+PUBLIC int
+altos_flush(struct altos_file *file)
+{
+       DWORD   put;
+       char    *data = file->out_data;
+       char    used = file->out_used;
+       DWORD   result;
 
-struct altos_file {
-       struct libusb_device            *device;
-       struct libusb_device_handle     *handle;
-       int                             out_ep;
-       int                             out_size;
-       int                             in_ep;
-       int                             in_size;
-       unsigned char                   out_data[USB_BUF_SIZE];
-       int                             out_used;
-       unsigned char                   in_data[USB_BUF_SIZE];
-       int                             in_used;
-       int                             in_read;
-};
+       while (used) {
+               if (!WriteFile(file->handle, data, used, &put, NULL)) {
+                       result = GetLastError();
+                       printf ("write failed %d\n", result);
+                       return LIBALTOS_ERROR;
+               }
+               data += put;
+               used -= put;
+       }
+       file->out_used = 0;
+       return LIBALTOS_SUCCESS;
+}
 
-struct altos_file *
+PUBLIC struct altos_file *
 altos_open(struct altos_device *device)
 {
-       struct altos_file               *file;
-       struct libusb_device_handle     *handle;
-       if (libusb_open(device->device, &handle) == 0) {
-               int     ret;
+       struct altos_file       *file = calloc (sizeof (struct altos_file), 1);
+       char    full_name[64];
 
-               ret = libusb_claim_interface(handle, 1);
-#if 0
-               if (ret) {
-                       libusb_close(handle);
-                       return NULL;
-               }
-#endif
-               ret = libusb_detach_kernel_driver(handle, 1);
-#if 0
-               if (ret) {
-                       libusb_close(handle);
-                       return NULL;
-               }
-#endif
+       if (!file)
+               return NULL;
 
-               file = calloc(sizeof (struct altos_file), 1);
-               file->device = libusb_ref_device(device->device);
-               file->handle = handle;
-               /* XXX should get these from the endpoint descriptors */
-               file->out_ep = 4 | LIBUSB_ENDPOINT_OUT;
-               file->out_size = 64;
-               file->in_ep = 5 | LIBUSB_ENDPOINT_IN;
-               file->in_size = 64;
+       strcpy(full_name, "\\\\.\\");
+       strcat(full_name, device->path);
+       file->handle = CreateFile(full_name, GENERIC_READ|GENERIC_WRITE,
+                                 0, NULL, OPEN_EXISTING,
+                                 FILE_ATTRIBUTE_NORMAL, NULL);
+       if (file->handle == INVALID_HANDLE_VALUE) {
+               free(file);
+               return NULL;
+       }
 
-               return file;
+       timeouts.ReadIntervalTimeout = MAXDWORD;
+       timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
+       timeouts.ReadTotalTimeoutConstant = 100;
+       timeouts.WriteTotalTimeoutMultiplier = 0;
+       timeouts.WriteTotalTimeoutConstant = 10000;
+       if (!SetCommTimeouts(file->handle, &timeouts)) {
+               printf("SetCommTimeouts failed %d\n", GetLastError());
        }
-       return NULL;
+
+       return file;
 }
 
-void
+PUBLIC void
 altos_close(struct altos_file *file)
 {
-       libusb_close(file->handle);
-       libusb_unref_device(file->device);
-       file->handle = NULL;
+       if (file->handle != INVALID_HANDLE_VALUE) {
+               CloseHandle(file->handle);
+               file->handle = INVALID_HANDLE_VALUE;
+       }
+}
+
+PUBLIC void
+altos_free(struct altos_file *file)
+{
+       altos_close(file);
        free(file);
 }
 
@@ -778,60 +944,29 @@ altos_putchar(struct altos_file *file, char c)
 {
        int     ret;
 
-       if (file->out_used == file->out_size) {
+       if (file->out_used == USB_BUF_SIZE) {
                ret = altos_flush(file);
                if (ret)
                        return ret;
        }
        file->out_data[file->out_used++] = c;
-       if (file->out_used == file->out_size)
+       if (file->out_used == USB_BUF_SIZE)
                return altos_flush(file);
-       return 0;
-}
-
-int
-altos_flush(struct altos_file *file)
-{
-       while (file->out_used) {
-               int     transferred;
-               int     ret;
-
-               ret = libusb_bulk_transfer(file->handle,
-                                          file->out_ep,
-                                          file->out_data,
-                                          file->out_used,
-                                          &transferred,
-                                          0);
-               if (ret)
-                       return ret;
-               if (transferred) {
-                       memmove(file->out_data, file->out_data + transferred,
-                               file->out_used - transferred);
-                       file->out_used -= transferred;
-               }
-       }
+       return LIBALTOS_SUCCESS;
 }
 
 int
 altos_getchar(struct altos_file *file, int timeout)
 {
+       int     ret;
        while (file->in_read == file->in_used) {
-               int     ret;
-               int     transferred;
-
-               altos_flush(file);
-               ret = libusb_bulk_transfer(file->handle,
-                                          file->in_ep,
-                                          file->in_data,
-                                          file->in_size,
-                                          &transferred,
-                                          (unsigned int) timeout);
+               if (file->handle == INVALID_HANDLE_VALUE)
+                       return LIBALTOS_ERROR;
+               ret = altos_fill(file, timeout);
                if (ret)
                        return ret;
-               file->in_read = 0;
-               file->in_used = transferred;
        }
        return file->in_data[file->in_read++];
 }
 
-#endif /* USE_LIBUSB */
+#endif