X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=ao-tools%2Flibaltos%2Flibaltos.c;h=ffdb23669964c2be417b0905e7cf5a862122fdf6;hp=417c8fe5688b2ff295b89ca6fc7e6afcb838b141;hb=f9e80f39bc39e5882bfe75f959b6501cb3277cd2;hpb=c726d8f6eb861801d7543552beab6ee2c920c96f;ds=sidebyside diff --git a/ao-tools/libaltos/libaltos.c b/ao-tools/libaltos/libaltos.c index 417c8fe5..ffdb2366 100644 --- a/ao-tools/libaltos/libaltos.c +++ b/ao-tools/libaltos/libaltos.c @@ -15,11 +15,344 @@ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#define BUILD_DLL #include "libaltos.h" +#include +#include +#include + +PUBLIC int +altos_init(void) +{ + return LIBALTOS_SUCCESS; +} + +PUBLIC void +altos_fini(void) +{ +} + +#ifdef DARWIN +/* Mac OS X don't have strndup even if _GNU_SOURCE is defined */ +static char * +altos_strndup (const char *s, size_t n) +{ + size_t len = strlen (s); + char *ret; + + if (len <= n) + return strdup (s); + ret = malloc(n + 1); + strncpy(ret, s, n); + ret[n] = '\0'; + return ret; +} + +#else +#define altos_strndup strndup +#endif + +/* + * Scan for Altus Metrum devices by looking through /sys + */ + +#ifdef LINUX -#define USE_DARWIN +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +static char * +cc_fullname (char *dir, char *file) +{ + char *new; + int dlen = strlen (dir); + int flen = strlen (file); + int slen = 0; + + if (dir[dlen-1] != '/') + slen = 1; + new = malloc (dlen + slen + flen + 1); + if (!new) + return 0; + strcpy(new, dir); + if (slen) + strcat (new, "/"); + strcat(new, file); + return new; +} + +static char * +cc_basename(char *file) +{ + char *b; + + b = strrchr(file, '/'); + if (!b) + return file; + return b + 1; +} + +static char * +load_string(char *dir, char *file) +{ + char *full = cc_fullname(dir, file); + char line[4096]; + char *r; + FILE *f; + int rlen; + + f = fopen(full, "r"); + free(full); + if (!f) + return NULL; + r = fgets(line, sizeof (line), f); + fclose(f); + if (!r) + return NULL; + rlen = strlen(r); + if (r[rlen-1] == '\n') + r[rlen-1] = '\0'; + return strdup(r); +} -#ifdef USE_DARWIN +static int +load_hex(char *dir, char *file) +{ + char *line; + char *end; + long i; + + line = load_string(dir, file); + if (!line) + return -1; + i = strtol(line, &end, 16); + free(line); + if (end == line) + return -1; + return i; +} + +static int +load_dec(char *dir, char *file) +{ + char *line; + char *end; + long i; + + line = load_string(dir, file); + if (!line) + return -1; + i = strtol(line, &end, 10); + free(line); + if (end == line) + return -1; + return i; +} + +static int +dir_filter_tty_colon(const struct dirent *d) +{ + return strncmp(d->d_name, "tty:", 4) == 0; +} + +static int +dir_filter_tty(const struct dirent *d) +{ + return strncmp(d->d_name, "tty", 3) == 0; +} + +struct altos_usbdev { + char *sys; + char *tty; + char *manufacturer; + char *product_name; + int serial; /* AltOS always uses simple integer serial numbers */ + int idProduct; + int idVendor; +}; + +static char * +usb_tty(char *sys) +{ + char *base; + int num_configs; + int config; + struct dirent **namelist; + int interface; + int num_interfaces; + char endpoint_base[20]; + char *endpoint_full; + char *tty_dir; + int ntty; + char *tty; + + base = cc_basename(sys); + num_configs = load_hex(sys, "bNumConfigurations"); + num_interfaces = load_hex(sys, "bNumInterfaces"); + for (config = 1; config <= num_configs; config++) { + for (interface = 0; interface < num_interfaces; interface++) { + sprintf(endpoint_base, "%s:%d.%d", + base, config, interface); + endpoint_full = cc_fullname(sys, endpoint_base); + + /* Check for tty:ttyACMx style names + */ + ntty = scandir(endpoint_full, &namelist, + dir_filter_tty_colon, + alphasort); + if (ntty > 0) { + free(endpoint_full); + tty = cc_fullname("/dev", namelist[0]->d_name + 4); + free(namelist); + return tty; + } + + /* Check for tty/ttyACMx style names + */ + tty_dir = cc_fullname(endpoint_full, "tty"); + free(endpoint_full); + ntty = scandir(tty_dir, &namelist, + dir_filter_tty, + alphasort); + free (tty_dir); + if (ntty > 0) { + tty = cc_fullname("/dev", namelist[0]->d_name); + free(namelist); + return tty; + } + } + } + return NULL; +} + +static struct altos_usbdev * +usb_scan_device(char *sys) +{ + struct altos_usbdev *usbdev; + + usbdev = calloc(1, sizeof (struct altos_usbdev)); + if (!usbdev) + return NULL; + usbdev->sys = strdup(sys); + usbdev->manufacturer = load_string(sys, "manufacturer"); + 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"); + usbdev->tty = usb_tty(sys); + return usbdev; +} + +static void +usbdev_free(struct altos_usbdev *usbdev) +{ + free(usbdev->sys); + free(usbdev->manufacturer); + free(usbdev->product_name); + /* this can get used as a return value */ + if (usbdev->tty) + free(usbdev->tty); + free(usbdev); +} + +#define USB_DEVICES "/sys/bus/usb/devices" + +static int +dir_filter_dev(const struct dirent *d) +{ + const char *n = d->d_name; + char c; + + while ((c = *n++)) { + if (isdigit(c)) + continue; + if (c == '-') + continue; + if (c == '.' && n != d->d_name + 1) + continue; + return 0; + } + return 1; +} + +struct altos_list { + struct altos_usbdev **dev; + int current; + int ndev; +}; + +struct altos_list * +altos_list_start(void) +{ + int e; + struct dirent **ents; + char *dir; + struct altos_usbdev *dev; + struct altos_list *devs; + int n; + + devs = calloc(1, sizeof (struct altos_list)); + if (!devs) + return NULL; + + n = scandir (USB_DEVICES, &ents, + dir_filter_dev, + alphasort); + if (!n) + return 0; + for (e = 0; e < n; e++) { + dir = cc_fullname(USB_DEVICES, ents[e]->d_name); + dev = usb_scan_device(dir); + free(dir); + if (USB_IS_ALTUSMETRUM(dev->idVendor, dev->idProduct)) { + if (devs->dev) + devs->dev = realloc(devs->dev, + devs->ndev + 1 * sizeof (struct usbdev *)); + else + devs->dev = malloc (sizeof (struct usbdev *)); + devs->dev[devs->ndev++] = dev; + } + } + free(ents); + devs->current = 0; + return devs; +} + +int +altos_list_next(struct altos_list *list, struct altos_device *device) +{ + struct altos_usbdev *dev; + if (list->current >= list->ndev) + return 0; + dev = list->dev[list->current]; + 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++; + return 1; +} + +void +altos_list_finish(struct altos_list *usbdevs) +{ + int i; + + if (!usbdevs) + return; + for (i = 0; i < usbdevs->ndev; i++) + usbdev_free(usbdevs->dev[i]); + free(usbdevs); +} + +#endif + +#ifdef DARWIN #include #include @@ -30,47 +363,32 @@ #include #include #include -#include -#include -#include -#include struct altos_list { - io_iterator_t iterator; + io_iterator_t iterator; }; static int get_string(io_object_t object, CFStringRef entry, char *result, int result_len) { - CFTypeRef entry_as_string; - Boolean got_string; - - entry_as_string = IORegistryEntrySearchCFProperty (object, - kIOServicePlane, - entry, - kCFAllocatorDefault, - kIORegistryIterateRecursively); - if (entry_as_string) { - got_string = CFStringGetCString(entry_as_string, - result, result_len, - kCFStringEncodingASCII); + CFTypeRef entry_as_string; + Boolean got_string; + + entry_as_string = IORegistryEntrySearchCFProperty (object, + kIOServicePlane, + entry, + kCFAllocatorDefault, + kIORegistryIterateRecursively); + if (entry_as_string) { + got_string = CFStringGetCString(entry_as_string, + result, result_len, + kCFStringEncodingASCII); - CFRelease(entry_as_string); - if (got_string) - return 1; - } - return 0; -} - -int -altos_init(void) -{ - return 1; -} - -void -altos_fini(void) -{ + CFRelease(entry_as_string); + if (got_string) + return 1; + } + return 0; } struct altos_list * @@ -117,70 +435,35 @@ altos_list_next(struct altos_list *list, struct altos_device *device) void altos_list_finish(struct altos_list *list) { - IOObjectRelease (list->iterator); - free(list); + IOObjectRelease (list->iterator); + free(list); } +#endif + +#ifdef POSIX_TTY + +#include +#include +#include +#include +#include +#include #define USB_BUF_SIZE 64 struct altos_file { int fd; + int pipe[2]; unsigned char out_data[USB_BUF_SIZE]; int out_used; unsigned char in_data[USB_BUF_SIZE]; int in_used; int in_read; + pthread_mutex_t putc_mutex; + pthread_mutex_t getc_mutex; }; -void -altos_test(char *path) -{ - int n; - char buf[16]; - int fd; - struct termios term; - - fd = open(path, O_RDWR | O_NOCTTY); - if (fd < 0) { - perror(path); - return; - } - if (ioctl(fd, TIOCEXCL, (char *) 0) < 0) { - perror("TIOCEXCL"); - close (fd); - return; - } - - n = tcgetattr(fd, &term); - if (n < 0) { - perror("tcgetattr"); - close(fd); - return; - } - cfmakeraw(&term); - term.c_cc[VMIN] = 0; - term.c_cc[VTIME] = 1; - n = tcsetattr(fd, TCSAFLUSH, &term); - if (n < 0) { - perror("tcsetattr"); - close(fd); - return; - } - write(fd, "\n?\n", 3); - for (;;) { - n = read(fd, buf, sizeof (buf)); - if (n < 0) { - perror("read"); - break; - } - if (n == 0) - break; - write(1, buf, n); - } - close(fd); -} - struct altos_file * altos_open(struct altos_device *device) { @@ -191,6 +474,7 @@ altos_open(struct altos_device *device) if (!file) return NULL; + pipe(file->pipe); file->fd = open(device->path, O_RDWR | O_NOCTTY); if (file->fd < 0) { perror(device->path); @@ -205,8 +489,8 @@ altos_open(struct altos_device *device) return NULL; } cfmakeraw(&term); - term.c_cc[VMIN] = 0; - term.c_cc[VTIME] = 1; + term.c_cc[VMIN] = 1; + term.c_cc[VTIME] = 0; ret = tcsetattr(file->fd, TCSAFLUSH, &term); if (ret < 0) { perror("tcsetattr"); @@ -214,38 +498,38 @@ altos_open(struct altos_device *device) free(file); return NULL; } + pthread_mutex_init(&file->putc_mutex,NULL); + pthread_mutex_init(&file->getc_mutex,NULL); return file; } void altos_close(struct altos_file *file) { - close(file->fd); - free(file); + if (file->fd != -1) { + int fd = file->fd; + file->fd = -1; + write(file->pipe[1], "\r", 1); + close(fd); + } } -int -altos_putchar(struct altos_file *file, char c) +void +altos_free(struct altos_file *file) { - int ret; - - 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 == USB_BUF_SIZE) - return altos_flush(file); - return 0; + altos_close(file); + free(file); } -int -altos_flush(struct altos_file *file) +static int +_altos_flush(struct altos_file *file) { while (file->out_used) { int ret; + if (file->fd < 0) + return -EBADF; + fflush(stdout); ret = write (file->fd, file->out_data, file->out_used); if (ret < 0) return -errno; @@ -258,110 +542,101 @@ altos_flush(struct altos_file *file) } int -altos_getchar(struct altos_file *file, int timeout) +altos_putchar(struct altos_file *file, char c) { - while (file->in_read == file->in_used) { - int ret; + int ret; - altos_flush(file); - ret = read(file->fd, file->in_data, USB_BUF_SIZE); - if (ret < 0) - return -errno; - file->in_read = 0; - file->in_used = ret; + pthread_mutex_lock(&file->putc_mutex); + if (file->out_used == USB_BUF_SIZE) { + ret = _altos_flush(file); + if (ret) { + pthread_mutex_unlock(&file->putc_mutex); + return ret; + } } - return file->in_data[file->in_read++]; -} - -#endif /* USE_DARWIN */ - -#ifdef USE_LIBUSB -#include -#include -#include -#include - -libusb_context *usb_context; - -int altos_init(void) -{ - int ret; - ret = libusb_init(&usb_context); - if (ret) - return ret; - libusb_set_debug(usb_context, 3); + file->out_data[file->out_used++] = c; + ret = 0; + if (file->out_used == USB_BUF_SIZE) + ret = _altos_flush(file); + pthread_mutex_unlock(&file->putc_mutex); return 0; } -void altos_fini(void) +int +altos_flush(struct altos_file *file) { - libusb_exit(usb_context); - usb_context = NULL; + int ret; + pthread_mutex_lock(&file->putc_mutex); + ret = _altos_flush(file); + pthread_mutex_unlock(&file->putc_mutex); + return ret; } -static libusb_device **list; -static ssize_t num, current; -int altos_list_start(void) +#include + +int +altos_getchar(struct altos_file *file, int timeout) { - 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; - } - return 1; -} + int ret; + struct pollfd fd[2]; + + if (timeout == 0) + timeout = -1; + pthread_mutex_lock(&file->getc_mutex); + fd[0].fd = file->fd; + fd[0].events = POLLIN; + fd[1].fd = file->pipe[0]; + fd[1].events = POLLIN; + while (file->in_read == file->in_used) { + if (file->fd < 0) { + pthread_mutex_unlock(&file->getc_mutex); + return LIBALTOS_ERROR; + } + altos_flush(file); -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; - } + ret = poll(fd, 2, timeout); + if (ret < 0) { + perror("altos_getchar"); + pthread_mutex_unlock(&file->getc_mutex); + return LIBALTOS_ERROR; + } + if (ret == 0) { + pthread_mutex_unlock(&file->getc_mutex); + return LIBALTOS_TIMEOUT; + } + if (fd[0].revents & POLLIN) { + ret = read(file->fd, file->in_data, USB_BUF_SIZE); + if (ret < 0) { + perror("altos_getchar"); + pthread_mutex_unlock(&file->getc_mutex); + return LIBALTOS_ERROR; } + file->in_read = 0; + file->in_used = ret; } } - return 0; + ret = file->in_data[file->in_read++]; + pthread_mutex_unlock(&file->getc_mutex); + return ret; } -void altos_list_finish(void) -{ - if (list) { - libusb_free_device_list(list, 1); - list = NULL; - } -} +#endif /* POSIX_TTY */ + +#ifdef WINDOWS + +#include +#include + +struct altos_list { + HDEVINFO dev_info; + int index; +}; #define USB_BUF_SIZE 64 struct altos_file { - struct libusb_device *device; - struct libusb_device_handle *handle; - int out_ep; - int out_size; - int in_ep; - int in_size; + HANDLE handle; unsigned char out_data[USB_BUF_SIZE]; int out_used; unsigned char in_data[USB_BUF_SIZE]; @@ -369,49 +644,234 @@ struct altos_file { int in_read; }; -struct altos_file * -altos_open(struct altos_device *device) + +PUBLIC struct altos_list * +altos_list_start(void) { - struct altos_file *file; - struct libusb_device_handle *handle; - if (libusb_open(device->device, &handle) == 0) { - int ret; + struct altos_list *list = calloc(1, sizeof (struct altos_list)); - ret = libusb_claim_interface(handle, 1); -#if 0 - if (ret) { - libusb_close(handle); - return NULL; + 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; + } + list->index = 0; + return list; +} + +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; } -#endif - ret = libusb_detach_kernel_driver(handle, 1); -#if 0 - if (ret) { - libusb_close(handle); - return NULL; + + /* 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; } -#endif - 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; + /* 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; + } - return file; + /* 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; } - return NULL; + result = GetLastError(); + if (result != ERROR_NO_MORE_ITEMS) + printf ("SetupDiEnumDeviceInfo failed error %d\n", result); + return 0; } -void +PUBLIC void +altos_list_finish(struct altos_list *list) +{ + 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; +} + +PUBLIC int +altos_flush(struct altos_file *file) +{ + DWORD put; + char *data = file->out_data; + char used = file->out_used; + DWORD result; + + 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; +} + +PUBLIC struct altos_file * +altos_open(struct altos_device *device) +{ + struct altos_file *file = calloc (sizeof (struct altos_file), 1); + char full_name[64]; + + if (!file) + return NULL; + + 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; + } + + 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 file; +} + +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); } @@ -420,60 +880,32 @@ 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); + ret = altos_flush(file); + if (ret) + return ret; + 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