/* * atrf-gpio/atusb.c - ATUSB-specific GPIO driver * * Written 2011 by Werner Almesberger * Copyright 2011 Werner Almesberger * * 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. */ #include #include #include #include "atusb/ep0.h" #include "atrf.h" #include "atrf-gpio.h" #define FROM_DEV ATUSB_FROM_DEV(0) static const char *name[24] = { "PB0", "PB1/P16", "PB2/P15", "PB3/P14", "PB4/SLP_TR", "PB5", "PB6/LED", "PB7", "PC0", "PC1/P13", "PC2", "PC3(NC)", "PC4", "PC5", "PC6", "PC7/nRST_RF", "PD0/IRQ_RF", "PD1/nSS", "PD2/MISO", "PD3/MOSI", "PD4", "PD5/SCLK", "PD6", "PD7" }; static struct atrf_dsc *orig_dsc; static uint8_t orig_data[3], orig_dir[3]; static void dump_port(int port, uint8_t data, uint8_t dir, uint8_t mask) { int i; fprintf(stderr, "name\t\tcfg\n"); for (i = 0; i != 8; i++) { int bit = 1 << (i & 7); fprintf(stderr, "%-16s%c\n", name[port*8+i], mask & bit ? dir & bit ? data & bit ? '1' : '0' : data & bit ? 'R' : 'Z' : 'x'); } } static uint8_t gpio(struct atrf_dsc *dsc, uint8_t port, uint8_t *data, uint8_t *dir, uint8_t mask) { uint8_t buf[3]; int res; res = usb_control_msg(atrf_usb_handle(dsc), FROM_DEV, ATUSB_GPIO, *dir << 8 | *data, mask << 8 | port, (void *) buf, sizeof(buf), 1000); if (res < 0) { dump_port(port-1, *data, *dir, mask); fprintf(stderr, "ATUSB_GPIO: %s\n", usb_strerror()); _exit(1); } if (res != 3) { fprintf(stderr, "ATUSB_GPIO: expected 3 bytes, got %d\n", res); _exit(1); } *data = buf[1]; *dir = buf[2]; return buf[0]; } static void dump(const uint8_t *data, const uint8_t *dir, const uint8_t *expect, const uint8_t *got, const uint8_t *read) { int i; fprintf(stderr, "name\t\tcfg exp got\n"); for (i = 0; i != 24; i++) { int port = i >> 3; int bit = 1 << (i & 7); fprintf(stderr, "%-16s%c %c %d", name[i], dir[port] & bit ? data[port] & bit ? '1' : '0' : data[port] & bit ? 'R' : 'Z', read[port] & bit ? expect[port] & bit ? '1' : '0' : '-', !!(got[port] & bit)); if ((expect[port] ^ got[port]) & read[port] & bit) fprintf(stderr, "\t***"); fputc('\n', stderr); } } /* ----- Decode and apply pattern ------------------------------------------ */ static void restore_gpios(void) { int i; for (i = 0; i != 3; i++) gpio(orig_dsc, i+1, orig_data+i, orig_dir+i, 0xff); } void do_atusb(struct atrf_dsc *dsc, const char *pattern, const char *next) { static int first = 1; const char *p; int i, pin = 0; uint8_t data[3], dir[3], mask[3], read[3], expect[3], got[3]; uint8_t bit; int port; data[0] = data[1] = data[2] = 0; dir[0] = dir[1] = dir[2] = 0; mask[0] = mask[1] = mask[2] = 0; read[0] = read[1] = read[2] = 0; expect[0] = expect[1] = expect[2] = 0; if (first) { orig_dsc = dsc; for (i = 0; i != 3; i++) gpio(dsc, i+1, orig_data+i, orig_dir+i, 0); atexit(restore_gpios); first = 0; } for (p = pattern; *p; p++) { bit = 1 << (pin & 7); port = pin >> 3; switch (*p) { case '1': data[port] |= bit; /* fall through */ case '0': dir[port] |= bit; mask[port] |= bit; break; case 'H': expect[port] |= bit; /* fall through */ case 'L': read[port] |= bit; /* fall through */ case 'Z': data[port] |= bit; mask[port] |= bit; break; case 'h': expect[port] |= bit; /* fall through */ case 'l': case 'o': read[port] |= bit; /* fall through */ case 'z': mask[port] |= bit; break; case 'x': pin++; continue; default: continue; } pin++; } for (i = 0; i <= port; i++) got[i] = gpio(dsc, i+1, data+i, dir+i, mask[i]); for (i = 0; i <= port; i++) if ((got[i] & read[i]) != expect[i]) { dump(data, dir, expect, got, read); fprintf(stderr, "at \"%s\", next \"%s\"\n", pattern, next); exit(1); } }