static int avrdoper_send(union filedescriptor *fdp, unsigned char *buf, size_t buflen) { if(verbose > 3) dumpBlock("Send", buf, buflen); while(buflen > 0){ unsigned char buffer[256]; int rval, lenIndex = chooseDataSize(buflen); int thisLen = buflen > reportDataSizes[lenIndex] ? reportDataSizes[lenIndex] : buflen; buffer[0] = lenIndex + 1; /* report ID */ buffer[1] = thisLen; memcpy(buffer + 2, buf, thisLen); if(verbose > 3) fprintf(stderr, "Sending %d bytes data chunk\n", thisLen); rval = usbSetReport(fdp, USB_HID_REPORT_TYPE_FEATURE, (char *)buffer, reportDataSizes[lenIndex] + 2); if(rval != 0){ fprintf(stderr, "%s: avrdoper_send(): %s\n", progname, usbErrorText(rval)); exit(1); } buflen -= thisLen; buf += thisLen; } return 0; }
/** * API: Set the backlight brightness */ void glcd2usb_backlight(PrivateData *p, int state) { int err = 0; CT_glcd2usb_data *ctd = (CT_glcd2usb_data *) p->ct_data; int promille = (state == BACKLIGHT_ON) ? p->brightness : p->offbrightness; ctd->tx_buffer.bytes[0] = GLCD2USB_RID_SET_BL; ctd->tx_buffer.bytes[1] = promille * 255 / 1000; p->glcd_functions->drv_debug(RPT_DEBUG, "glcd2usb_backlight: new value = %d", ctd->tx_buffer.bytes[1]); if ((err = usbSetReport(ctd->device, USB_HID_REPORT_TYPE_FEATURE, ctd->tx_buffer.bytes, 2)) != 0) { p->glcd_functions->drv_report(RPT_ERR, "Error freeing display: %s\n", usbErrorMessage(err)); } }
/** * API: Initialize glcd2usb connection type. */ int glcd2usb_init(Driver *drvthis) { PrivateData *p = (PrivateData *)drvthis->private_data; CT_glcd2usb_data *ctd; static int didUsbInit = 0; struct usb_bus *bus; struct usb_device *dev; usb_dev_handle *handle = NULL; int err = 0; int rval, retries = 3; int len; /* Set up connection type low-level functions */ p->glcd_functions->blit = glcd2usb_blit; p->glcd_functions->close = glcd2usb_close; p->glcd_functions->set_backlight = glcd2usb_backlight; p->glcd_functions->poll_keys = glcd2usb_poll_keys; /* Allocate memory structures */ ctd = (CT_glcd2usb_data *) calloc(1, sizeof(CT_glcd2usb_data)); if (ctd == NULL) { report(RPT_ERR, "%s/glcd2usb: error allocating connection data", drvthis->name); return -1; } p->ct_data = ctd; /* * Try to find and open a device. Only the first device found will be * recognized. */ if (!didUsbInit) { usb_init(); didUsbInit = 1; } usb_find_busses(); usb_find_devices(); for (bus = usb_get_busses(); bus != NULL; bus = bus->next) { for (dev = bus->devices; dev != NULL; dev = dev->next) { if (dev->descriptor.idVendor == GLCD2USB_VID && dev->descriptor.idProduct == GLCD2USB_PID) { handle = usb_open(dev); if (!handle) { report(RPT_WARNING, "%s/glcd2usb: cannot open USB device: %s", drvthis->name, usb_strerror()); continue; } else { goto found_dev; } } } } found_dev: if (handle) { debug(RPT_DEBUG, "%s/glcd2usb: opening device succeeded", drvthis->name); } else { report(RPT_ERR, "%s/glcd2usb: no GLCD2USB device found", drvthis->name); goto err_out; } if (usb_set_configuration(handle, 1)) report(RPT_WARNING, "%s/glcd2usb: could not set configuration: %s", drvthis->name, usb_strerror()); /* * now try to claim the interface and detach the kernel HID driver on * Linux and other operating systems which support the call. */ while ((rval = usb_claim_interface(handle, 0)) != 0 && retries-- > 0) { #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP if (usb_detach_kernel_driver_np(handle, 0) < 0) { report(RPT_WARNING, "%s/glcd2usb: could not detach kernel HID driver: %s", drvthis->name, usb_strerror()); } #endif } if (rval != 0) report(RPT_WARNING, "%s/glcd2usb: could not claim interface", drvthis->name); /* * Continue anyway, even if we could not claim the interface. Control * transfers should still work. */ ctd->device = handle; /* Query device */ memset(&(ctd->tx_buffer), 0, sizeof(ctd->tx_buffer)); len = sizeof(display_info_t); if ((err = usbGetReport(ctd->device, USB_HID_REPORT_TYPE_FEATURE, GLCD2USB_RID_GET_INFO, ctd->tx_buffer.bytes, &len)) != 0) { report(RPT_ERR, "%s/glcd2usb: query display parameters: %s", drvthis->name, usbErrorMessage(err)); goto err_out; } if (len < (int)sizeof(ctd->tx_buffer.display_info)) { report(RPT_ERR, "%s/glcd2usb: incomplete display info report (%d instead of %d)", drvthis->name, len, (int)sizeof(ctd->tx_buffer.display_info)); goto err_out; } if (!(ctd->tx_buffer.display_info.flags & FLAG_VERTICAL_UNITS)) { report(RPT_ERR, "%s/glcd2usb: unsupported display layout", drvthis->name); goto err_out; } if (ctd->tx_buffer.display_info.width > GLCD_MAX_WIDTH || ctd->tx_buffer.display_info.width <= 0 || ctd->tx_buffer.display_info.height > GLCD_MAX_HEIGHT || ctd->tx_buffer.display_info.height <= 0) { report(RPT_ERR, "%s/glcd2usb: display size out of range: %dx%d", drvthis->name, ctd->tx_buffer.display_info.width, ctd->tx_buffer.display_info.height); goto err_out; } p->framebuf.layout = FB_TYPE_VPAGED; p->framebuf.px_width = ctd->tx_buffer.display_info.width; p->framebuf.px_height = ctd->tx_buffer.display_info.height; p->framebuf.size = (p->framebuf.px_height + 7) / 8 * p->framebuf.px_width; report(RPT_INFO, "%s/glcd2usb: using display size %dx%d", drvthis->name, ctd->tx_buffer.display_info.width, ctd->tx_buffer.display_info.height); ctd->paged_buffer = malloc(p->framebuf.size); if (ctd->paged_buffer == NULL) { report(RPT_ERR, "%s/glcd2usb: cannot allocate memory", drvthis->name); goto err_out; } memset(ctd->paged_buffer, 0x55, p->framebuf.size); ctd->dirty_buffer = malloc(p->framebuf.size); if (ctd->dirty_buffer == NULL) { report(RPT_ERR, "%s/glcd2usb: cannot allocate memory", drvthis->name); goto err_out; } /* Allocate the display (turn off the 'whirl') */ ctd->tx_buffer.bytes[0] = GLCD2USB_RID_SET_ALLOC; ctd->tx_buffer.bytes[1] = 1; if ((err = usbSetReport(ctd->device, USB_HID_REPORT_TYPE_FEATURE, ctd->tx_buffer.bytes, 2)) != 0) { report(RPT_ERR, "%s/glcd2usb: Error allocating display: %s", drvthis->name, usbErrorMessage(err)); goto err_out; } return 0; err_out: glcd2usb_close(p); return -1; }
/** * API: Transfer an image to the glcd2usb device. This function and its update * algorithm are copied from the LCD4Linux driver as it does its job well. */ void glcd2usb_blit(PrivateData *p) { CT_glcd2usb_data *ctd = (CT_glcd2usb_data *) p->ct_data; int r; int i, j; int err; int pos; p->glcd_functions->drv_debug(RPT_DEBUG, "glcd2usb_blit: starting"); /* Reset the dirty buffer */ memset(ctd->dirty_buffer, 0x00, p->framebuf.size); /* * Step 1: Compare the content of the secondary buffer with the frame * buffer and copy the differences. For each different byte, set the * flag in the dirty buffer. */ for (pos = 0; pos < p->framebuf.size; pos++) { if (ctd->paged_buffer[pos] != p->framebuf.data[pos]) { ctd->paged_buffer[pos] = p->framebuf.data[pos]; ctd->dirty_buffer[pos] = 1; } } /* * Step 2: Short gaps of unchanged bytes in fact increase the * communication overhead. So we eliminate them here. */ for (j = -1, i = 0; i < p->framebuf.size; i++) { if (ctd->dirty_buffer[i] && j >= 0 && i - j <= 4) { /* found a clean gap <= 4 bytes: mark it dirty */ for (r = j; r < i; r++) ctd->dirty_buffer[r] = 1; } /* if this is dirty, drop the saved position */ if (ctd->dirty_buffer[i]) j = -1; /* save position of this clean entry if no position saved yet */ if (!ctd->dirty_buffer[i] && j < 0) j = i; } /* Step 3: Send the changes. */ ctd->tx_buffer.bytes[0] = 0; for (i = 0; i < p->framebuf.size; i++) { if (ctd->dirty_buffer[i]) { /* Start a new packet */ if (!ctd->tx_buffer.bytes[0]) { ctd->tx_buffer.bytes[0] = GLCD2USB_RID_WRITE; ctd->tx_buffer.bytes[1] = i % 256; ctd->tx_buffer.bytes[2] = i / 256; ctd->tx_buffer.bytes[3] = 0; /* length */ } /* Append the dirty byte and increase size */ ctd->tx_buffer.bytes[4 + ctd->tx_buffer.bytes[3]++] = ctd->paged_buffer[i]; } /* * Send the data if we hit a clean byte, are at the end of * the frame or reached the maximum payload for a write * request. */ if (!ctd->dirty_buffer[i] || i == p->framebuf.size - 1 || ctd->tx_buffer.bytes[3] == 128) { /* Only write if there IS something to be written */ if (ctd->tx_buffer.bytes[0] == GLCD2USB_RID_WRITE && ctd->tx_buffer.bytes[3] > 0) { err = usbSetReport(ctd->device, USB_HID_REPORT_TYPE_FEATURE, ctd->tx_buffer.bytes, ctd->tx_buffer.bytes[3] + 4); if (err) p->glcd_functions->drv_report(RPT_ERR, "glcd2usb_blit: error in transfer"); /* Start a new packet the next time */ ctd->tx_buffer.bytes[0] = 0; } } } }
static int uploadData(char *dataBuffer) { usbDevice_t *dev = NULL; int err = 0, len, mask, pageSize, deviceSize, i; union{ char bytes[1]; deviceInfo_t info; deviceData_t data; } buffer; if((err = usbOpenDevice(&dev, IDENT_VENDOR_NUM, IDENT_VENDOR_STRING, IDENT_PRODUCT_NUM, IDENT_PRODUCT_STRING, 1)) != 0){ fprintf(stderr, "Error opening HIDBoot device: %s\n", usbErrorMessage(err)); goto errorOccurred; } len = sizeof(buffer); if(endAddress[addressIndex] > startAddress[0]){ // we need to upload data if((err = usbGetReport(dev, USB_HID_REPORT_TYPE_FEATURE, 1, buffer.bytes, &len)) != 0){ fprintf(stderr, "Error reading page size: %s\n", usbErrorMessage(err)); goto errorOccurred; } if(len < sizeof(buffer.info)){ fprintf(stderr, "Not enough bytes in device info report (%d instead of %d)\n", len, (int)sizeof(buffer.info)); err = -1; goto errorOccurred; } pageSize = getUsbInt(buffer.info.pageSize, 2); deviceSize = getUsbInt(buffer.info.flashSize, 4); printf("Page size = %d (0x%x)\n", pageSize, pageSize); printf("Device size = %d (0x%x); %d bytes remaining\n", deviceSize, deviceSize, deviceSize - 2048); if(endAddress[addressIndex] > deviceSize - 2048){ fprintf(stderr, "Data (%d bytes) exceeds remaining flash size!\n", endAddress[addressIndex]); err = -1; goto errorOccurred; } if(pageSize < 128){ mask = 127; }else{ mask = pageSize - 1; } for (i = 0; i <= addressIndex; i++) { startAddress[i] &= ~mask; /* round down */ endAddress[i] = (endAddress[i] + mask) & ~mask; /* round up */ printf("Uploading %d (0x%x) bytes starting at %d (0x%x)\n", endAddress[i] - startAddress[i], endAddress[i] - startAddress[i], startAddress[i], startAddress[i]); while(startAddress[i] < endAddress[i]){ buffer.data.reportId = 2; memcpy(buffer.data.data, dataBuffer + startAddress[i], 128); setUsbInt(buffer.data.address, startAddress[i], 3); printf("\r0x%05x ... 0x%05x", startAddress[i], startAddress[i] + (int)sizeof(buffer.data.data)); fflush(stdout); if((err = usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buffer.bytes, sizeof(buffer.data))) != 0){ //fprintf(stderr, "Error uploading data block: %s\n", usbErrorMessage(err)); continue; goto errorOccurred; } startAddress[i] += sizeof(buffer.data.data); } printf("\n"); } } if(leaveBootLoader){ /* and now leave boot loader: */ buffer.info.reportId = 1; usbSetReport(dev, USB_HID_REPORT_TYPE_FEATURE, buffer.bytes, sizeof(buffer.info)); /* Ignore errors here. If the device reboots before we poll the response, * this request fails. */ } errorOccurred: if(dev != NULL) usbCloseDevice(dev); return err; }