From 464847c5b25588448e550017a6d91447c076b944 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Wed, 23 Nov 2016 21:23:09 +0000 Subject: init commit --- halfkay.c | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 halfkay.c (limited to 'halfkay.c') diff --git a/halfkay.c b/halfkay.c new file mode 100644 index 0000000..c2a92a9 --- /dev/null +++ b/halfkay.c @@ -0,0 +1,164 @@ +/* HalfKay implementation + * Based on Teensy Loader (cli) (http://www.pjrc.com/teensy/loader_cli.html) + * + * Copyright (C) 2016 Tomasz Kramkowski + * + * 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 3 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, see . + */ + +#define _DEFAULT_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "halfkay.h" +#include "log.h" + +enum { + HK_USB_VID = 0x16c0, + HK_USB_PID = 0x0478, + HK_USB_REQTYP = (LIBUSB_ENDPOINT_OUT \ + | LIBUSB_REQUEST_TYPE_CLASS \ + | LIBUSB_RECIPIENT_INTERFACE), + HK_USB_REQ = LIBUSB_REQUEST_SET_CONFIGURATION, + HK_USB_VAL = 0x200, +}; + +libusb_device_handle *hk_usb_hnd; + +static inline void libusb_err(const char *action, int code) +{ + error(0, "libusb %s failed: %s", action, libusb_strerror(code)); +} + +static void usbopen(void) +{ + int rc; + + rc = libusb_init(NULL); + if (libusb_init(NULL) != LIBUSB_SUCCESS) + libusb_err("init", rc); + + hk_usb_hnd = libusb_open_device_with_vid_pid(NULL, HK_USB_VID, HK_USB_PID); + if (!hk_usb_hnd) + error(0, "HalfKay device not found"); + + libusb_set_auto_detach_kernel_driver(hk_usb_hnd, 1); + rc = libusb_claim_interface(hk_usb_hnd, 0); + if (rc < 0) + libusb_err("claim", rc); +} + +static void usbclose(void) +{ + libusb_release_interface(hk_usb_hnd, 0); + libusb_close(hk_usb_hnd); + libusb_exit(NULL); +} + +static void usbsendcmd(void *data, size_t size, bool firstxfer) +{ + unsigned int timeout = firstxfer ? 3000 : 2000; + int rc; + + rc = libusb_control_transfer(hk_usb_hnd, HK_USB_REQTYP, HK_USB_REQ, + HK_USB_VAL, 0, data, size, timeout); + + if (rc < 0) + libusb_err("transfer", rc); + + /* TODO: Replace this with the correct way to handle a halt... ffs idiot */ + usleep(10000); /* HalfKay says no if you write too fast */ +} + +static void fmtcmd(void *_dest, const struct flashparams *fp, size_t addr) +{ + unsigned char *dest = _dest; + + addr >>= fp->addrshft; + for (size_t i = 0; i < fp->cmdsz; i++) + dest[i] = (addr >> (i * CHAR_BIT)) & 0xFF; +} + +int flash(const struct flashparams *fp, const char *file) +{ + FILE *f; + unsigned char *cmd; + size_t tsize; + + assert(file); + + /* TODO: move checks to parser */ + /*if (!fp->blksz || !(fp->blksz & fp->blksz - 1))*/ + /*error(0, "Block size is not a power of 2");*/ + /*if (fp->memsz % fp->blksz)*/ + /*error(0, "Memory size is not divisible by block size");*/ + + tsize = fp->blksz + fp->cmdsz; + + f = fopen(file, "rb"); + if (!f) + error(errno, EMSG_OPEN, file); + + /* TODO: precalc and check ovf */ + cmd = malloc(tsize); + if (!cmd) + error(errno, EMSG_ALLOC); + + usbopen(); + + for (size_t blkaddr = 0; blkaddr < fp->memsz; blkaddr += fp->blksz) { + size_t count; + + fmtcmd(cmd, fp, blkaddr); + count = fread(cmd + fp->cmdsz, 1, fp->blksz, f); + if (count == 0) + break; + if (count < fp->blksz) { + memset(cmd + fp->cmdsz + count, 0, fp->blksz - count); + } + + usbsendcmd(cmd, tsize, blkaddr == 0); + } + + if (!feof(f)) + fprintf(stderr, "Device ran out of space during writing!"); + + usbclose(); + + free(cmd); + fclose(f); + + return 0; +} + +int reboot(const struct flashparams *fp) +{ + size_t tsize = fp->blksz + fp->cmdsz; + unsigned char *cmd = malloc(tsize); + + usbopen(); + + fmtcmd(cmd, fp, SIZE_MAX); + usbsendcmd(cmd, tsize, true); + + usbclose(); + + return 0; +} -- cgit v1.2.3-54-g00ecf