Merge ccdbg and altos sources into one giant repository
[fw/altos] / lib / cp-usb-async.c
index 3f5f76abe482ffd417dc6f32f54792c49bd259bf..6539394b541a95ec4c2761d75d7a9c739e253048 100644 (file)
@@ -38,6 +38,8 @@ struct cp_usb_async {
        libusb_device_handle    *handle;
        struct cp_usb_packet    packet[MAX_OUTSTANDING];
        int                     p, ack;
+       uint8_t                 value;
+       uint8_t                 set;
 };
 
 struct cp_usb_async *
@@ -56,11 +58,14 @@ cp_usb_async_open(void)
        }
        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;
 }
 
@@ -103,9 +108,16 @@ void
 cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value)
 {
        int     p;
-       uint16_t gpio_set = ((uint16_t) value << 8) | mask;
+       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;
@@ -118,7 +130,7 @@ cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value)
                                  0x37e1,               /* value */
                                  gpio_set,             /* index */
                                  0);                   /* length */
-       
+
        libusb_fill_control_transfer(cp->packet[p].transfer,
                                     cp->handle,
                                     cp->packet[p].data,
@@ -151,7 +163,7 @@ cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep)
                                  0x00c2,               /* value */
                                  0,                    /* index */
                                  1);                   /* length */
-       
+
        libusb_fill_control_transfer(cp->packet[p].transfer,
                                     cp->handle,
                                     cp->packet[p].data,
@@ -172,5 +184,5 @@ cp_usb_async_sync(struct cp_usb_async *cp)
                libusb_handle_events(cp->ctx);
        }
        cp->p = 0;
-       cp->ack = 0;
+       cp->ack = -1;
 }