X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=cctools%2Flib%2Fcp-usb-async.c;fp=cctools%2Flib%2Fcp-usb-async.c;h=6539394b541a95ec4c2761d75d7a9c739e253048;hp=0000000000000000000000000000000000000000;hb=208bc15714c7b4020c017eef19011c4eb9ab51e2;hpb=17d2432a8b9c15963cd3b821f025ad33972ef477 diff --git a/cctools/lib/cp-usb-async.c b/cctools/lib/cp-usb-async.c new file mode 100644 index 00000000..6539394b --- /dev/null +++ b/cctools/lib/cp-usb-async.c @@ -0,0 +1,188 @@ +/* + * Copyright © 2008 Keith Packard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 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 General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include +#include +#include +#include +#include "cp-usb-async.h" +#include "ccdbg-debug.h" + +#define MAX_OUTSTANDING 256 +#define CP_TIMEOUT 1000 /* ms */ + +struct cp_usb_packet { + struct libusb_transfer *transfer; + enum { packet_read, packet_write } direction; + unsigned char data[9]; + uint8_t *valuep; +}; + +struct cp_usb_async { + libusb_context *ctx; + libusb_device_handle *handle; + struct cp_usb_packet packet[MAX_OUTSTANDING]; + int p, ack; + uint8_t value; + uint8_t set; +}; + +struct cp_usb_async * +cp_usb_async_open(void) +{ + struct cp_usb_async *cp; + int ret; + + cp = calloc(sizeof (struct cp_usb_async), 1); + if (!cp) + return NULL; + ret = libusb_init(&cp->ctx); + if (ret) { + free(cp); + return NULL; + } + cp->handle = libusb_open_device_with_vid_pid(cp->ctx, + 0x10c4, 0xea60); + cp->ack = -1; + if (!cp->handle) { + libusb_exit(cp->ctx); + free(cp); + return NULL; + } + cp->value = 0; + cp->set = 0; + return cp; +} + +void +cp_usb_async_close(struct cp_usb_async *cp) +{ + libusb_close(cp->handle); + libusb_exit(cp->ctx); + free(cp); +} + +static void +cp_usb_async_transfer_callback(struct libusb_transfer *transfer) +{ + struct cp_usb_async *cp = transfer->user_data; + int p; + + for (p = 0; p < cp->p; p++) + if (cp->packet[p].transfer == transfer) + break; + if (p == cp->p) { + fprintf(stderr, "unknown transfer\n"); + return; + } + switch (cp->packet[p].direction) { + case packet_read: + ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack read %d 0x%02x\n", + p, cp->packet[p].data[8]); + *cp->packet[p].valuep = cp->packet[p].data[8]; + break; + case packet_write: + ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack write %d\n", p); + break; + } + if (p > cp->ack) + cp->ack = p; +} + +void +cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value) +{ + int p; + uint16_t gpio_set; + int ret; + + if (cp->set) { + value = (cp->value & ~mask) | (value & mask); + mask = value ^ cp->value; + } + cp->set = 1; + cp->value = value; + gpio_set = ((uint16_t) value << 8) | mask; + if (cp->p == MAX_OUTSTANDING) + cp_usb_async_sync(cp); + p = cp->p; + if (!cp->packet[p].transfer) + cp->packet[p].transfer = libusb_alloc_transfer(0); + cp->packet[p].direction = packet_write; + libusb_fill_control_setup(cp->packet[p].data, + 0x40, /* request */ + 0xff, /* request type */ + 0x37e1, /* value */ + gpio_set, /* index */ + 0); /* length */ + + libusb_fill_control_transfer(cp->packet[p].transfer, + cp->handle, + cp->packet[p].data, + cp_usb_async_transfer_callback, + cp, + CP_TIMEOUT); + ccdbg_debug(CC_DEBUG_USB_ASYNC, "Write packet %d 0x%x 0x%x\n", p, mask, value); + ret = libusb_submit_transfer(cp->packet[p].transfer); + if (ret) + fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); + cp->p++; +} + +void +cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep) +{ + int p; + int ret; + + if (cp->p == MAX_OUTSTANDING) + cp_usb_async_sync(cp); + p = cp->p; + if (!cp->packet[p].transfer) + cp->packet[p].transfer = libusb_alloc_transfer(0); + cp->packet[p].valuep = valuep; + cp->packet[p].direction = packet_read; + libusb_fill_control_setup(cp->packet[p].data, + 0xc0, /* request */ + 0xff, /* request type */ + 0x00c2, /* value */ + 0, /* index */ + 1); /* length */ + + libusb_fill_control_transfer(cp->packet[p].transfer, + cp->handle, + cp->packet[p].data, + cp_usb_async_transfer_callback, + cp, + CP_TIMEOUT); + ccdbg_debug(CC_DEBUG_USB_ASYNC, "Read packet %d\n", p); + ret = libusb_submit_transfer(cp->packet[p].transfer); + if (ret) + fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); + cp->p++; +} + +void +cp_usb_async_sync(struct cp_usb_async *cp) +{ + while (cp->ack < cp->p - 1) { + libusb_handle_events(cp->ctx); + } + cp->p = 0; + cp->ack = -1; +}