1
0
mirror of git://projects.qi-hardware.com/ben-wpan.git synced 2024-11-25 01:03:09 +02:00
ben-wpan/tools/atrf-gpio/atusb.c

196 lines
4.2 KiB
C

/*
* 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 <stdlib.h>
#include <stdio.h>
#include <usb.h>
#include "atusb/ep0.h"
#include "atrf.h"
#include "atrf-gpio.h"
#define FROM_DEV ATUSB_FROM_DEV(0)
#define TO_DEV ATUSB_TO_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, res;
for (i = 0; i != 3; i++)
gpio(orig_dsc, i+1, orig_data+i, orig_dir+i, 0xff);
res = usb_control_msg(atrf_usb_handle(orig_dsc),
TO_DEV, ATUSB_GPIO_CLEANUP, 0, 0, NULL, 0, 1000);
if (res < 0) {
fprintf(stderr, "ATUSB_GPIO_CLEANUP: %s\n", usb_strerror());
_exit(1);
}
}
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);
}
}