summaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJames McKenzie <git@madingley.org>2014-12-15 12:05:41 +0000
committerJames McKenzie <git@madingley.org>2014-12-15 12:05:41 +0000
commit373bb32332b117236720af0ff971769fc5930ba6 (patch)
treec1a1e58218a9ce1fed33b7e5330069f856c209cc /kernel
downloadvalve-373bb32332b117236720af0ff971769fc5930ba6.tar.gz
valve-373bb32332b117236720af0ff971769fc5930ba6.tar.bz2
valve-373bb32332b117236720af0ff971769fc5930ba6.zip
Diffstat (limited to 'kernel')
-rw-r--r--kernel/code/Makefile15
-rw-r--r--kernel/code/gpio.c49
-rw-r--r--kernel/code/libradiator.c463
-rw-r--r--kernel/code/program_radiator.c23
-rw-r--r--kernel/code/radiator.c34
-rw-r--r--kernel/code/radiator.h19
-rw-r--r--kernel/code/set.c63
-rw-r--r--kernel/code/thing.c207
-rw-r--r--kernel/cp2103-3.11.10.patch491
9 files changed, 1364 insertions, 0 deletions
diff --git a/kernel/code/Makefile b/kernel/code/Makefile
new file mode 100644
index 0000000..a478c0c
--- /dev/null
+++ b/kernel/code/Makefile
@@ -0,0 +1,15 @@
+
+PROGS=radiator program_radiator
+CSRCS=libradiator.c
+
+OBJS=${CSRCS:%.c=%.o}
+
+default:${PROGS}
+
+
+${PROGS}: %:%.o ${OBJS}
+ ${CC} -o $@ ${OBJS} $@.o
+
+
+clean:
+ /bin/rm -f core ${OBJS} ${PROGS} ${PROGS:%=%.o}
diff --git a/kernel/code/gpio.c b/kernel/code/gpio.c
new file mode 100644
index 0000000..549eb81
--- /dev/null
+++ b/kernel/code/gpio.c
@@ -0,0 +1,49 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <linux/cp210x.h>
+
+
+#define log_ioctl(fd,op,arg) do_ioctl(fd,#op,op,arg)
+
+int
+do_ioctl (int fd, char *sop, int op, void *arg)
+{
+ int ret;
+
+ errno = 0;
+
+ ret = ioctl (fd, op, arg);
+
+ printf ("ioctl(%d,%s(0x%x),%p)=%d (errno=%d(%s))\n", fd, sop, op, arg, ret,
+ errno, strerror (errno));
+
+ return ret;
+}
+
+int
+main (int argc, char *argv[])
+{
+ struct cp210x_port_config config;
+
+ int fd = open (argv[1], O_RDWR);
+
+ memset (&config, 0, sizeof (config));
+
+ log_ioctl (fd, CPIOC_PORTCONFGET, &config);
+
+ printf ("reset=(%x,%x,%x), suspend=(%x,%x,%x), enhanced_fxn=%x\n",
+ config.reset.mode,
+ config.reset.low_power,
+ config.reset.latch,
+ config.suspend.mode,
+ config.suspend.low_power,
+ config.suspend.latch, config.enhanced_fxn);
+
+
+}
diff --git a/kernel/code/libradiator.c b/kernel/code/libradiator.c
new file mode 100644
index 0000000..7baed2e
--- /dev/null
+++ b/kernel/code/libradiator.c
@@ -0,0 +1,463 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <malloc.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/cp210x.h>
+#include <sys/termios.h>
+
+#include "radiator.h"
+
+
+
+
+
+/*
+ * bit 0: 1 left leg NPN base
+ * bit 1: 2 left leg PNP base
+ * bit 2: 4 right leg PNP base
+ * bit 3: 8 right leg NPN base
+ */
+
+#define LEFT_NPN_OFF 0
+#define LEFT_NPN_ON 1
+#define LEFT_PNP_OFF 2
+#define LEFT_PNP_ON 0
+
+#define LEFT_LOW (LEFT_NPN_ON | LEFT_PNP_OFF)
+#define LEFT_HI (LEFT_NPN_OFF | LEFT_PNP_ON)
+#define LEFT_OFF (LEFT_NPN_OFF | LEFT_PNP_OFF)
+
+#define RIGHT_NPN_OFF 0
+#define RIGHT_NPN_ON 8
+#define RIGHT_PNP_OFF 4
+#define RIGHT_PNP_ON 0
+
+
+#define RIGHT_LOW (RIGHT_NPN_ON | RIGHT_PNP_OFF)
+#define RIGHT_HI (RIGHT_NPN_OFF | RIGHT_PNP_ON)
+#define RIGHT_OFF (RIGHT_NPN_OFF | RIGHT_PNP_OFF)
+
+#define BRAKE (RIGHT_LOW | LEFT_LOW)
+#define FORWARDS (RIGHT_LOW | LEFT_HI)
+#define BACKWARDS (RIGHT_HI | LEFT_LOW)
+#define OFF (RIGHT_OFF| LEFT_OFF)
+
+#define TIMEOUT 750000 /*75ms */
+#define RUN_IN 50
+#define RELEASE_TENSION 10
+
+static int brake_motor(int fd)
+{
+ int i=BRAKE;
+ printf (" Motor braking\n");
+ return ioctl (fd, CPIOC_GPIOSET, &i);
+}
+
+static int
+drive_motor (int fd, int dir)
+{
+ int i;
+
+ if (dir > 0)
+ {
+ printf (" Motor forwards\n");
+ i = FORWARDS;
+ }
+ else if (dir < 0)
+ {
+ printf (" Motor backwards\n");
+ i = BACKWARDS;
+ }
+ else
+ {
+ printf (" Motor off\n");
+ i = OFF;
+ }
+
+
+ return ioctl (fd, CPIOC_GPIOSET, &i);
+}
+
+static int
+sensor_led_power (int fd, int on)
+{
+ int i = TIOCM_DTR;
+
+ printf (" Rotation sensor power %s\n", on ? "on" : "off");
+
+ return ioctl (fd, on ? TIOCMBIS : TIOCMBIC, &i);
+}
+
+
+#if 0
+static int
+count_steps (int fd, int count)
+{
+ struct timeval tv, tv_changed, tv_diff;
+ int cts, old_cts = -1;
+ int counted = 0;
+
+ printf (" Counting %d steps", count);
+
+ gettimeofday (&tv_changed, NULL);
+
+ while (count)
+ {
+ ioctl (fd, TIOCMGET, &cts);
+ cts &= TIOCM_CTS;
+
+ if (cts != old_cts)
+ {
+ if (cts)
+ {
+ counted++;
+ count--;
+ printf (".");
+ fflush (stdout);
+ }
+ gettimeofday (&tv_changed, NULL);
+ old_cts = cts;
+ }
+ gettimeofday (&tv, NULL);
+ timersub (&tv, &tv_changed, &tv_diff);
+
+ if (tv_diff.tv_sec || (tv_diff.tv_usec > TIMEOUT))
+ break;
+
+ }
+
+ printf ("%d steps\n", counted);
+ return counted;
+}
+#else
+count_steps (int fd, int count)
+{
+ int counted = 0;
+ struct timeval tv;
+ char buf[128];
+ int i;
+ fd_set rfds;
+
+ printf (" Counting %d steps", count);
+
+FD_ZERO(&rfds);
+
+tcflush(fd,TCIFLUSH);
+
+
+ while (count)
+ {
+ tv.tv_sec=0;
+ tv.tv_usec=TIMEOUT;
+ FD_SET(fd,&rfds);
+
+ if (!select(fd+1,&rfds,NULL,NULL,&tv)) break;
+
+ i=read(fd,buf,sizeof(buf));
+ if (i<0) continue;
+
+ counted+=i;
+ if (count>0) {
+ count-=i;
+ if (count<0) count=0;
+ }
+
+ printf (".");
+ fflush (stdout);
+ }
+
+ printf ("%d steps\n", counted);
+ return counted;
+}
+#endif
+
+
+
+
+static int
+drive_motor_count (Radiator * r, int dir, int steps)
+{
+ int s1, s2, ret;
+
+ sensor_led_power (r->fd, 1);
+ drive_motor (r->fd, dir);
+ s1 = count_steps (r->fd, steps);
+ if (s1 != steps) {
+ printf (" Hit end stop\n");
+ drive_motor (r->fd, 0);
+ } else {
+ brake_motor(r->fd);
+ }
+ s2 = count_steps (r->fd, -1);
+ sensor_led_power (r->fd, 0);
+ drive_motor (r->fd, 0);
+
+ /*did we hit an end stop? */
+ if (s1 != steps)
+ ret = s1 - s2;
+ else
+ ret = s1 + s2;
+
+ printf (" %d steps under power (of %d), %d steps coasting -> %d steps\n",
+ s1, steps, s2, ret);
+
+ r->pos += ret * dir;
+
+ /*Recalibrate our notion of ends */
+
+ if (s1 != steps)
+ {
+ if (dir == -1)
+ {
+ r->pos = 0;
+ }
+ else
+ {
+ r->max = r->pos;
+ }
+ }
+
+ return ret;
+}
+
+
+
+
+int
+radiator_set_pos (Radiator * r, int wanted)
+{
+ int guard, delta;
+
+ delta = wanted - r->pos;
+ printf ("Now at %d want %d, delta %d\n", r->pos, wanted, delta);
+
+ if (wanted == 0)
+ {
+ drive_motor_count (r, -1, -1);
+ return 0;
+ }
+ else if (r->max && (wanted >= r->max))
+ {
+ drive_motor_count (r, 1, -1);
+ return 0;
+ }
+
+
+ guard = r->overshoot * 3;
+
+ if ((delta > -guard) && (delta < guard))
+ {
+ printf ("Too close\n");
+
+ drive_motor_count (r, (r->pos > r->half) ? -1 : 1, RUN_IN);
+
+ delta = wanted - r->pos;
+ printf ("Now at %d want %d, delta %d\n", r->pos, wanted, delta);
+ }
+
+
+ if (delta < 0)
+ {
+ drive_motor_count (r, -1, (-delta) - r->overshoot);
+ }
+ else if (delta > 0)
+ {
+ drive_motor_count (r, 1, delta - r->overshoot);
+ }
+
+ printf ("Wanted %d, got %d\n", wanted, r->pos);
+
+ return 0;
+}
+
+int
+radiator_calibrate (Radiator * r)
+{
+ radiator_set_pos (r, 0);
+
+ drive_motor_count (r, 1, RUN_IN);
+
+ r->overshoot = r->pos - RUN_IN;
+}
+
+
+static int utf16(uint8_t *dst,uint8_t *src)
+{
+int len=0;
+
+
+while (*src) {
+ *(dst++)=*(src++);
+ len+=2;
+ *(dst++)=0;
+}
+
+return len;
+}
+
+
+static void make_usb_descriptor(uint8_t *dst,uint8_t *src)
+{
+int len;
+len=utf16(dst+2,src);
+dst[0]=len+2;
+dst[1]=0x3;
+}
+
+
+
+
+int
+radiator_program (Radiator * r)
+{
+ struct cp210x_port_config config;
+ uint8_t buf[256];
+
+
+#if 0
+ memset (&config, 0, sizeof (config));
+ ioctl (r->fd, CPIOC_PORTCONFGET, &config);
+
+
+ printf
+ ("config was reset=(%x,%x,%x), suspend=(%x,%x,%x), enhanced_fxn=%x\n",
+ config.reset.mode, config.reset.low_power, config.reset.latch,
+ config.suspend.mode, config.suspend.low_power, config.suspend.latch,
+ config.enhanced_fxn);
+
+
+ memset (&config, 0, sizeof (config));
+
+ config.reset.mode = ~CP_INPUT_PINS;
+ config.reset.low_power = 0;
+ config.reset.latch = CP_INPUT_PINS | CP_PIN_GPIO_1 | CP_PIN_GPIO_2;
+ config.suspend.mode = ~CP_INPUT_PINS;
+ config.suspend.low_power = 0;
+ config.suspend.latch = CP_INPUT_PINS | CP_PIN_GPIO_1 | CP_PIN_GPIO_2;
+ config.enhanced_fxn = CP_EFXN_ENABLE_WPU;
+
+ ioctl (r->fd, CPIOC_PORTCONFSET, &config);
+
+ memset (&config, 0, sizeof (config));
+ ioctl (r->fd, CPIOC_PORTCONFGET, &config);
+
+
+ printf
+ ("config is reset=(%x,%x,%x), suspend=(%x,%x,%x), enhanced_fxn=%x\n",
+ config.reset.mode, config.reset.low_power, config.reset.latch,
+ config.suspend.mode, config.suspend.low_power, config.suspend.latch,
+ config.enhanced_fxn);
+
+#endif
+ memset(buf,0,sizeof(buf));
+
+{
+int i=0x413c;
+ ioctl (r->fd, CPIOC_SETVID, &i);
+}
+
+{
+int i=0x9500;
+ ioctl (r->fd, CPIOC_SETPID, &i);
+}
+
+ make_usb_descriptor(buf,"USB Radiator Valve");
+ ioctl (r->fd, CPIOC_SETPRODUCT, buf);
+
+ make_usb_descriptor(buf,"000001");
+ ioctl (r->fd, CPIOC_SETSERIAL, buf);
+
+#if 0
+ make_usb_descriptor(buf,"Global Panaceas");
+ ioctl (r->fd, CPIOC_SETMFG, buf);
+#endif
+
+
+ ioctl (r->fd, CPIOC_DEVICERESET, 0);
+
+
+
+
+ return 0;
+}
+
+
+static void tty_setup(int fd)
+{
+struct termios tios;
+
+tcgetattr(fd, &tios);
+
+cfmakeraw( &tios);
+
+ tios.c_iflag = PARMRK | INPCK;
+ tios.c_oflag = NL0 | CR0 | TAB0 | BS0 | VT0 | FF0;
+ tios.c_lflag = 0;
+ tios.c_cflag = CS8 | CREAD | CLOCAL;
+ tios.c_cc[VMIN]=1;
+ tios.c_cc[VTIME]=0;
+
+ cfsetispeed (&tios, B115200);
+ cfsetospeed (&tios, B115200);
+
+ tcsetattr (fd, TCSANOW, &tios);
+}
+
+
+
+static void
+set_nonblocking (int fd)
+{
+ long arg = 0;
+ arg = fcntl (fd, F_GETFL, arg);
+ arg |= O_NONBLOCK;
+ fcntl (fd, F_SETFL, arg);
+}
+
+static void
+set_blocking (int fd)
+{
+ long arg = 0;
+ arg = fcntl (fd, F_GETFL, arg);
+ arg &= ~O_NONBLOCK;
+ fcntl (fd, F_SETFL, arg);
+}
+
+
+Radiator *
+radiator_open (char *s, int quiet)
+{
+ Radiator *r = malloc (sizeof (Radiator));
+
+ r->fd = open (s, O_RDWR |O_NOCTTY);
+
+ if (r->fd < 0)
+ {
+ free (r);
+ return NULL;
+ }
+
+ tty_setup(r->fd);
+ set_nonblocking(r->fd);
+
+ r->half = 5 * RUN_IN;
+ r->overshoot = 0;
+ r->max = 0;
+ r->pos = 0;
+
+ if (!quiet)
+ radiator_calibrate (r);
+}
+
+void
+radiator_close (Radiator * r)
+{
+ close (r->fd);
+ free (r);
+}
diff --git a/kernel/code/program_radiator.c b/kernel/code/program_radiator.c
new file mode 100644
index 0000000..75077da
--- /dev/null
+++ b/kernel/code/program_radiator.c
@@ -0,0 +1,23 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "radiator.h"
+
+int
+main (int argc, char *argv[])
+{
+ Radiator *r;
+ int pos;
+ char buf[1024];
+
+
+ r = radiator_open (argv[1],1);
+
+ if (!r)
+ return -1;
+
+ radiator_program(r);
+
+ return 0;
+}
diff --git a/kernel/code/radiator.c b/kernel/code/radiator.c
new file mode 100644
index 0000000..2d594da
--- /dev/null
+++ b/kernel/code/radiator.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "radiator.h"
+
+int
+main (int argc, char *argv[])
+{
+ Radiator *r;
+ int pos;
+ char buf[1024];
+
+
+ r = radiator_open (argv[1],0);
+
+ if (!r)
+ return -1;
+
+
+ for (;;)
+ {
+ printf ("Current position %d (end stop at %d, overshoots by %d)\n",
+ r->pos, r->max, r->overshoot);
+ printf ("Enter new>");
+ fflush (stdout);
+ buf[sizeof (buf) - 1] = 0;
+ fgets (buf, sizeof (buf) - 1, stdin);
+ radiator_set_pos (r, atoi (buf));
+ }
+
+
+ return 0;
+}
diff --git a/kernel/code/radiator.h b/kernel/code/radiator.h
new file mode 100644
index 0000000..a16edb8
--- /dev/null
+++ b/kernel/code/radiator.h
@@ -0,0 +1,19 @@
+#ifndef _RADIATOR_H_
+#define _RADIATOR_H_
+
+typedef struct
+{
+ int fd;
+ int pos;
+ int half;
+ int overshoot;
+ int max;
+} Radiator;
+
+int radiator_set_pos (Radiator * r, int wanted);
+int radiator_calibrate (Radiator * r);
+int radiator_program (Radiator * r);
+Radiator *radiator_open (char *s, int quiet);
+void radiator_close (Radiator * r);
+
+#endif /* _RADIATOR_H_ */
diff --git a/kernel/code/set.c b/kernel/code/set.c
new file mode 100644
index 0000000..4c8de0e
--- /dev/null
+++ b/kernel/code/set.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <linux/cp210x.h>
+
+
+#define log_ioctl(fd,op,arg) do_ioctl(fd,#op,op,arg)
+
+int
+do_ioctl (int fd, char *sop, int op, void *arg)
+{
+ int ret;
+
+ errno = 0;
+
+ ret = ioctl (fd, op, arg);
+
+ printf ("ioctl(%d,%s(0x%x),%p)=%d (errno=%d(%s))\n", fd, sop, op, arg, ret,
+ errno, strerror (errno));
+
+ return ret;
+}
+
+int
+main (int argc, char *argv[])
+{
+ struct cp210x_port_config config;
+
+ int fd = open (argv[1], O_RDWR);
+
+ memset (&config, 0, sizeof (config));
+
+// config.reset.mode=0xf05f;
+ config.reset.mode = ~CP_INPUT_PINS;
+ config.reset.low_power = 0;
+ config.reset.latch = CP_INPUT_PINS | CP_PIN_GPIO_1 | CP_PIN_GPIO_2;
+// config.suspend.mode=0xf05f;
+ config.suspend.mode = ~CP_INPUT_PINS;
+ config.suspend.low_power = 0;
+ config.suspend.latch = CP_INPUT_PINS | CP_PIN_GPIO_1 | CP_PIN_GPIO_2;
+// config.enhanced_fxn=0x30;
+ config.enhanced_fxn = CP_EFXN_ENABLE_WPU;
+
+
+ log_ioctl (fd, CPIOC_PORTCONFSET, &config);
+ log_ioctl (fd, CPIOC_PORTCONFGET, &config);
+
+ printf ("reset=(%x,%x,%x), suspend=(%x,%x,%x), enhanced_fxn=%x\n",
+ config.reset.mode,
+ config.reset.low_power,
+ config.reset.latch,
+ config.suspend.mode,
+ config.suspend.low_power,
+ config.suspend.latch, config.enhanced_fxn);
+
+ log_ioctl (fd, CPIOC_DEVICERESET, 0);
+
+}
diff --git a/kernel/code/thing.c b/kernel/code/thing.c
new file mode 100644
index 0000000..d9b5eac
--- /dev/null
+++ b/kernel/code/thing.c
@@ -0,0 +1,207 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <linux/cp210x.h>
+
+/*
+ * bit 0: 1 left leg NPN base
+ * bit 1: 2 left leg PNP base
+ * bit 2: 4 right leg PNP base
+ * bit 3: 8 right leg NPN base
+ */
+
+#define LEFT_NPN_OFF 0
+#define LEFT_NPN_ON 1
+#define LEFT_PNP_OFF 2
+#define LEFT_PNP_ON 0
+
+#define LEFT_LOW (LEFT_NPN_ON | LEFT_PNP_OFF)
+#define LEFT_HI (LEFT_NPN_OFF | LEFT_PNP_ON)
+#define LEFT_OFF (LEFT_NPN_OFF | LEFT_PNP_OFF)
+
+#define RIGHT_NPN_OFF 0
+#define RIGHT_NPN_ON 8
+#define RIGHT_PNP_OFF 4
+#define RIGHT_PNP_ON 0
+
+
+#define RIGHT_LOW (RIGHT_NPN_ON | RIGHT_PNP_OFF)
+#define RIGHT_HI (RIGHT_NPN_OFF | RIGHT_PNP_ON)
+#define RIGHT_OFF (RIGHT_NPN_OFF | RIGHT_PNP_OFF)
+
+#define FORWARDS (RIGHT_LOW | LEFT_HI)
+#define BACKWARDS (RIGHT_HI | LEFT_LOW)
+#define OFF (RIGHT_OFF| LEFT_OFF)
+
+#define TIMEOUT 750000 /*75ms */
+#define RUN_IN 50
+#define RELEASE_TENSION 10
+
+int
+drive_motor (int fd, int dir)
+{
+ int i;
+
+ if (dir > 0)
+ {
+ printf (" Motor forwards\n");
+ i = FORWARDS;
+ }
+ else if (dir < 0)
+ {
+ printf (" Motor backwards\n");
+ i = BACKWARDS;
+ }
+ else
+ {
+ printf (" Motor off\n");
+ i = OFF;
+ }
+
+
+ return ioctl (fd, CPIOC_GPIOSET, &i);
+}
+
+int
+sensor_led_power (int fd, int on)
+{
+ int i = TIOCM_DTR;
+
+ printf (" Rotation sensor power %s\n", on ? "on" : "off");
+
+ return ioctl (fd, on ? TIOCMBIS : TIOCMBIC, &i);
+}
+
+
+static int
+count_steps (int fd, int count)
+{
+ struct timeval tv, tv_changed, tv_diff;
+ int cts, old_cts = -1;
+ int counted = 0;
+
+ printf (" Counting %d steps", count);
+
+ gettimeofday (&tv_changed, NULL);
+
+ while (count)
+ {
+ ioctl (fd, TIOCMGET, &cts);
+ cts &= TIOCM_CTS;
+
+ if (cts != old_cts)
+ {
+ if (cts)
+ {
+ counted++;
+ count--;
+ printf (".");
+ fflush (stdout);
+ }
+ gettimeofday (&tv_changed, NULL);
+ old_cts = cts;
+ }
+ gettimeofday (&tv, NULL);
+ timersub (&tv, &tv_changed, &tv_diff);
+
+ if (tv_diff.tv_sec || (tv_diff.tv_usec > TIMEOUT))
+ break;
+
+ }
+
+ printf ("%d steps\n", counted);
+ return counted;
+}
+
+
+
+
+static int
+drive_motor_home (int fd)
+{
+ int ret;
+ sensor_led_power (fd, 1);
+ drive_motor (fd, -1);
+ ret = count_steps (fd, -1);
+ drive_motor (fd, 0);
+ ret -= count_steps (fd, -1);
+ sensor_led_power (fd, 0);
+ return ret;
+}
+
+static int
+drive_motor_count (int fd, int dir, int steps)
+{
+ int ret;
+ sensor_led_power (fd, 1);
+ drive_motor (fd, dir);
+ ret = count_steps (fd, steps);
+ drive_motor (fd, 0);
+ ret += count_steps (fd, -1);
+ sensor_led_power (fd, 0);
+ return ret;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int overshoot, guard, pos, wanted, delta;
+
+ int fd = open (argv[1], O_RDWR);
+
+ if (fd < 0)
+ return -1;
+
+
+ pos = drive_motor_home (fd);
+
+ printf ("Motor was %d steps from home\n", pos);
+
+
+ if (argc == 2)
+ {
+ pos = drive_motor_count (fd, 1, RELEASE_TENSION);
+
+ printf ("Motor now %d steps from home\n", pos);
+ return 0;
+ }
+
+ pos = drive_motor_count (fd, 1, RUN_IN);
+
+ overshoot = pos - RUN_IN; /*overshot */
+
+ wanted = atoi (argv[2]);
+
+ delta = wanted - pos;
+ printf ("Now at %d want %d, delta %d\n", pos, wanted, delta);
+
+ guard = overshoot * 3;
+
+ if ((delta > -guard) && (delta < guard))
+ {
+ printf ("Too close\n");
+ pos += drive_motor_count (fd, 1, RUN_IN);
+ delta = wanted - pos;
+ printf ("Now at %d want %d, delta %d\n", pos, wanted, delta);
+ }
+
+
+ if (delta < 0)
+ {
+ pos -= drive_motor_count (fd, -1, (-delta) - overshoot);
+ }
+ else if (delta > 0)
+ {
+ pos += drive_motor_count (fd, 1, delta - overshoot);
+ }
+
+ printf ("Wanted %d steps, got %d steps\n", wanted, pos);
+
+ return 0;
+}
diff --git a/kernel/cp2103-3.11.10.patch b/kernel/cp2103-3.11.10.patch
new file mode 100644
index 0000000..949d962
--- /dev/null
+++ b/kernel/cp2103-3.11.10.patch
@@ -0,0 +1,491 @@
+diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
+index 0eae4ba..3e0b558 100644
+--- a/drivers/usb/serial/cp210x.c
++++ b/drivers/usb/serial/cp210x.c
+@@ -23,14 +23,22 @@
+ #include <linux/usb.h>
+ #include <linux/uaccess.h>
+ #include <linux/usb/serial.h>
++#include <linux/cp210x.h>
+
+ #define DRIVER_DESC "Silicon Labs CP210x RS232 serial adaptor driver"
+
++#define CP210x_MAX_DEVICE_STRLEN 256
++#define CP210x_MAX_PRODUCT_STRLEN 126
++#define CP210x_MAX_SERIAL_STRLEN 63
++#define CP210x_MAX_MAXPOWER 250
++
++
+ /*
+ * Function Prototypes
+ */
+ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *);
+ static void cp210x_close(struct usb_serial_port *);
++static int cp210x_ioctl(struct tty_struct *, struct file *, unsigned long);
+ static void cp210x_get_termios(struct tty_struct *, struct usb_serial_port *);
+ static void cp210x_get_termios_port(struct usb_serial_port *port,
+ unsigned int *cflagp, unsigned int *baudp);
+@@ -198,6 +206,7 @@ static struct usb_serial_driver cp210x_device = {
+ .bulk_out_size = 256,
+ .open = cp210x_open,
+ .close = cp210x_close,
++ .ioctl = cp210x_ioctl,
+ .break_ctl = cp210x_break_ctl,
+ .set_termios = cp210x_set_termios,
+ .tiocmget = cp210x_tiocmget,
+@@ -286,6 +295,185 @@ static struct usb_serial_driver * const serial_drivers[] = {
+ #define CONTROL_WRITE_DTR 0x0100
+ #define CONTROL_WRITE_RTS 0x0200
+
++
++
++/*
++ * cp210x_ctlmsg
++ * A generic usb control message interface.
++ * Returns the actual size of the data read or written within the message, 0
++ * if no data were read or written, or a negative value to indicate an error.
++ */
++static int cp210x_ctlmsg(struct usb_serial_port *port, u8 request,
++ u8 requestype, u16 value, u16 index, void *data, u16 size)
++{
++ struct usb_serial *serial = port->serial;
++ u8 *tbuf;
++ int ret;
++
++ if (!(tbuf = kmalloc(size, GFP_KERNEL)))
++ return -ENOMEM;
++ if (requestype & 0x80) {
++ ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), request,
++ requestype, value, index, tbuf, size, 300);
++ if (ret > 0 && size)
++ memcpy(data, tbuf, size);
++ } else {
++ if (size)
++ memcpy(tbuf, data, size);
++ ret = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), request,
++ requestype, value, index, tbuf, size, 300);
++ }
++ kfree(tbuf);
++ if (ret < 0 && ret != -EPIPE) {
++ dev_err(&port->dev, "cp210x: control failed cmd rqt %u "
++ "rq %u len %u ret %d\n", requestype, request, size, ret);
++ }
++ return ret;
++}
++
++
++static int cp210x_reset(struct usb_serial_port *port)
++{
++ /* Is this better than usb_device_reset? It may be. Once a client issues
++ * the reset ioctl, it must disconnect and reconnect, since the USB
++ * connections are torn down. We also ignore the error return, since
++ * the part resets and doesn't send one...
++ */
++ cp210x_ctlmsg(port, 0xff, 0x40, 0x0008, 0x00, 0, 0);
++
++ return 0;
++}
++
++// // cp210x_get_partnum
++
++static inline int cp210x_setu16(struct usb_serial_port *port, int cmd,
++ unsigned int value)
++{
++ return cp210x_ctlmsg(port, 0xff, 0x40, 0x3700 | (cmd & 0xff),
++ value, 0, 0);
++}
++
++
++// make_usb_string
++/*
++ * cp210x_setstr
++ *
++ * Set a USB string descriptor using proprietary cp210x control messages.
++ * Return the number of characters actually written.
++ */
++static int cp210x_setstr(struct usb_serial_port *port, int cmd, uint8_t *usbstr,size_t len)
++{
++ int ret = cp210x_ctlmsg(port, 0xff, 0x40, 0x3700 | (cmd & 0xff), 0,
++ usbstr, len);
++ dbg("%s - cmd 0x%02x len %d ret %d", __FUNCTION__, cmd, len, ret);
++ printk(KERN_ERR "%s - cmd 0x%02x len %d ret %d %x %x %x %x %x %x", __FUNCTION__, cmd, len, ret,
++ usbstr[0],usbstr[1],usbstr[2],usbstr[3],usbstr[4],usbstr[5]);
++ return ret;
++}
++
++
++
++/* Set all gpio simultaneously */
++static int cp210x_gpioset(struct usb_serial_port *port, int gpio)
++{
++ dbg("%s - port %d, gpio = 0x%.2x", __FUNCTION__, port->number, gpio);
++
++ return cp210x_ctlmsg(port, 0xff, 0x40, 0x37e1,
++ ((uint16_t)gpio << 8) | CP_GPIO_MASK, 0, 0);
++}
++
++/* Set select gpio bits */
++static int cp210x_gpiosetb(struct usb_serial_port *port, int set, int clear)
++{
++ u16 gpio = 0;
++
++ gpio |= set | clear;
++ gpio |= set << 8;
++
++ dbg("%s - port %d, gpiob = 0x%.4x", __FUNCTION__, port->number, gpio);
++
++ /* FIXME: how about REQTYPE_HOST_TO_DEVICE instead of 0x40? */
++ return cp210x_ctlmsg(port, 0xff, 0x40, 0x37e1, gpio, 0, 0);
++}
++
++static int cp210x_gpioget(struct usb_serial_port *port, int *gpio_ret)
++{
++ int ret;
++ u8 gpio;
++
++ dbg("%s - port %d", __FUNCTION__, port->number);
++
++ /* FIXME: how about REQTYPE_DEVICE_TO_HOST instead of 0xc0? */
++ ret = cp210x_ctlmsg(port, 0xff, 0xc0, 0x00c2, 0, &gpio, 1);
++
++ dbg("%s - gpio = 0x%.2x (%d)", __FUNCTION__, gpio, ret);
++
++ *gpio_ret=gpio;
++
++ return (ret == 1) ? 0 : -EPROTO;
++}
++
++static int cp210x_portconfset(struct usb_serial_port *port,
++ struct cp210x_port_config *config)
++{
++ struct cp210x_port_config be_config;
++ int ret;
++
++ dbg("%s", __FUNCTION__);
++
++ memset(&be_config, 0, sizeof(be_config));
++
++ be_config.reset.mode = cpu_to_be16(config->reset.mode);
++ be_config.reset.low_power = 0; // cpu_to_be16(config->reset.low_power);
++ be_config.reset.latch = cpu_to_be16(config->reset.latch);
++
++ be_config.suspend.mode = cpu_to_be16(config->suspend.mode);
++ be_config.suspend.low_power = 0; // cpu_to_be16(config->suspend.low_power);
++ be_config.suspend.latch = cpu_to_be16(config->suspend.latch);
++
++ be_config.enhanced_fxn = config->enhanced_fxn;
++
++
++ ret = cp210x_ctlmsg(port, 0xff, 0x40, 0x370c, 0, &be_config, sizeof(be_config));
++ if (ret == sizeof(be_config))
++ return 0;
++ else if (ret >= 0)
++ return -EPROTO;
++ else
++ return ret;
++}
++
++static int cp210x_portconfget(struct usb_serial_port *port,
++ struct cp210x_port_config *config)
++{
++ int ret;
++
++ dbg("%s", __FUNCTION__);
++
++ ret = cp210x_ctlmsg(port, 0xff, 0xc0, 0x370c, 0, config, sizeof(*config));
++
++ if (ret != sizeof(*config))
++ return (ret >= 0) ? -EPROTO : ret;
++
++ /* Words from cp2103 are MSB */
++
++ config->reset.mode = be16_to_cpu(config->reset.mode);
++ config->reset.low_power = be16_to_cpu(config->reset.low_power);
++ config->reset.latch = be16_to_cpu(config->reset.latch);
++
++ config->suspend.mode = be16_to_cpu(config->suspend.mode);
++ config->suspend.low_power = be16_to_cpu(config->suspend.low_power);
++ config->suspend.latch = be16_to_cpu(config->suspend.latch);
++
++ /* apparently not implemented yet */
++ config->reset.low_power = 0;
++ config->suspend.low_power = 0;
++
++ return 0;
++}
++
++
++
+ /*
+ * cp210x_get_config
+ * Reads from the CP210x configuration registers
+@@ -469,6 +657,163 @@ static void cp210x_close(struct usb_serial_port *port)
+ cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_DISABLE);
+ }
+
++static int cp210x_string_ioctl(struct usb_serial_port *port, unsigned long arg, int cmd,size_t max_len)
++{
++ uint8_t buf[CP210x_MAX_STRLEN];
++ size_t len;
++
++ if (copy_from_user(buf,(uint8_t *)arg,1))
++ return -EFAULT;
++
++ len=buf[0];
++
++ if (len>max_len)
++ return -EMSGSIZE;
++
++ if (copy_from_user(buf,(uint8_t *)arg,len))
++ return -EFAULT;
++
++ if (len && cp210x_setstr(port, cmd, buf, len) != len)
++ return -EPROTO;
++
++ return 0;
++}
++
++
++static int cp210x_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg)
++{
++ struct usb_serial_port *port = tty->driver_data;
++ struct cp210x_port_config config;
++ int iarg;
++ int ret = -ENOIOCTLCMD;
++
++ dbg("%s (%d) cmd = 0x%04x", __FUNCTION__, port->number, cmd);
++
++ switch (cmd) {
++ case CPIOC_GPIOGET:
++ /*if (cp210x_get_partnum(port) != CP210x_CP2103_VERSION) break; */
++ ret = cp210x_gpioget(port, &iarg);
++
++ if (ret)
++ break;
++
++ if (copy_to_user((int *)arg, &iarg, sizeof(iarg)))
++ ret = -EFAULT;
++
++ break;
++
++ case CPIOC_GPIOSET:
++ /*if (cp210x_get_partnum(port) != CP210x_CP2103_VERSION) break; */
++
++ if (copy_from_user(&iarg,(int *)arg, sizeof(iarg))) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = cp210x_gpioset(port, iarg);
++
++ break;
++
++ case CPIOC_GPIOBIS:
++ /*if (cp210x_get_partnum(port) != CP210x_CP2103_VERSION) break; */
++
++ if (copy_from_user(&iarg, (int *)arg, sizeof(iarg))) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = cp210x_gpiosetb(port, iarg, 0);
++
++ break;
++
++ case CPIOC_GPIOBIC:
++ /*if (cp210x_get_partnum(port) != CP210x_CP2103_VERSION) break; */
++
++ if (copy_from_user(&iarg, (int *)arg, sizeof(iarg))) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = cp210x_gpiosetb(port, 0, iarg);
++
++ break;
++
++ case CPIOC_DEVICERESET:
++ ret = cp210x_reset(port);
++ break;
++
++ case CPIOC_PORTCONFGET:
++ ret = cp210x_portconfget(port, &config);
++
++ if (ret) break;
++
++ if (copy_to_user((struct cp210x_port_state *)arg, &config, sizeof(config)))
++ ret = -EFAULT;
++
++ break;
++
++ case CPIOC_PORTCONFSET:
++ if (copy_from_user(&config, (struct cp210x_port_state *)arg, sizeof(config))) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = cp210x_portconfset(port, &config);
++ break;
++
++ case CPIOC_SETVID:
++ if (copy_from_user(&iarg, (int *)arg,sizeof(iarg))) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = cp210x_setu16(port, 0x01, iarg);
++
++ break;
++
++ case CPIOC_SETPID:
++ if (copy_from_user(&iarg, (int *)arg,sizeof(iarg))) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = cp210x_setu16(port, 0x02, iarg);
++
++ break;
++
++ case CPIOC_SETMFG:
++ ret = cp210x_string_ioctl(port, arg, 0x0, CP210x_MAX_MFG_STRLEN);
++ break;
++
++ case CPIOC_SETPRODUCT:
++ ret = cp210x_string_ioctl(port, arg, 0x3, CP210x_MAX_PRODUCT_STRLEN);
++
++ break;
++
++ case CPIOC_SETSERIAL:
++ ret = cp210x_string_ioctl(port, arg, 0x3, CP210x_MAX_SERIAL_STRLEN);
++ break;
++
++ case CPIOC_SETDEVVER:
++ if (copy_from_user(&iarg, (int *)arg,sizeof(iarg))) {
++ ret = -EFAULT;
++ break;
++ }
++
++ ret = cp210x_setu16(port, 0x07, iarg);
++
++ break;
++ default:
++ dbg("%s not supported = 0x%04x", __FUNCTION__, cmd);
++ break;
++ }
++
++ return ret;
++}
++
++
++
++
+ /*
+ * cp210x_get_termios
+ * Reads the baud rate, data bits, parity, stop bits and flow control mode
+diff --git a/include/linux/cp210x.h b/include/linux/cp210x.h
+new file mode 100644
+index 0000000..39faf96
+--- /dev/null
++++ b/include/linux/cp210x.h
+@@ -0,0 +1,100 @@
++/*
++ *
++ */
++#ifndef _CPIO210X_H
++#define _CPIO210X_H
++
++#define CP210X_IOCTL_BASE 'C'
++
++//struct watchdog_info {
++// __u32 options; /* Options the card/driver supports */
++// __u32 firmware_version; /* Firmware version of the card */
++// __u8 identity[32]; /* Identity of the board */
++//};
++
++struct cp210x_port_state {
++ uint16_t mode; /* push-pull = 1, open-drain = 0 */
++ uint16_t low_power; /* 1 = ground the pin, and disable */
++ uint16_t latch;
++} __attribute__((packed));
++
++/* LOPWR MODE LATCH */
++/* 0 0 0 Pin drivers are totem pole, and inital config sinks current to GND */
++/* 0 0 1 Pin drivers are totem pole, and inital config sources current from VIO */
++/* 0 1 0 Pin drivers are open drain, and inital config sinks current to GND */
++/* 0 1 1 Pin drivers are open drain, and inital config leaves pin HI-Z (you want this for inputs) */
++/* 1 X X Pin drivers are disabled, and pin sinks current to GND */
++
++
++struct cp210x_port_config {
++ struct cp210x_port_state reset;
++ struct cp210x_port_state suspend;
++ uint8_t enhanced_fxn;
++} __attribute__((packed));
++
++
++#define CP_PIN_RI (1 << 0)
++#define CP_PIN_DCD (1 << 1)
++#define CP_PIN_DTR (1 << 2)
++#define CP_PIN_DSR (1 << 3)
++#define CP_PIN_TXD (1 << 4)
++#define CP_PIN_RXD (1 << 5)
++#define CP_PIN_RTS (1 << 6)
++#define CP_PIN_CTS (1 << 7)
++#define CP_PIN_GPIO_0 (1 << 8)
++#define CP_PIN_GPIO_1 (1 << 9)
++#define CP_PIN_GPIO_2 (1 << 10)
++#define CP_PIN_GPIO_3 (1 << 11)
++#define CP_PIN_UNUSED_1 (1 << 12)
++#define CP_PIN_UNUSED_2 (1 << 13)
++#define CP_PIN_GPIO_SUSPEND (1 << 14)
++#define CP_PIN_GPIO_NSUSPEND (1 << 15)
++
++#define CP_INPUT_PINS (CP_PIN_RXD|CP_PIN_CTS|CP_PIN_DSR|CP_PIN_RI|CP_PIN_DCD)
++
++
++#define CP_EFXN_GPIO_0_IS_TXLED (1 << 0)
++#define CP_EFXN_GPIO_1_IS_RXLED (1 << 1)
++#define CP_EFXN_GPIO_2_IS_RS485_TX (1 << 2)
++#define CP_EFXN_UNUSED_1 (1 << 3) /* Set to zero */
++#define CP_EFXN_ENABLE_WPU (1 << 4)
++#define CP_EFXN_UNUSED_2 (1 << 5) /* Set to zero */
++#define CP_EFXN_SERIAL_AUTOOFF (1 << 6)
++#define CP_EFXN_GPIOL_AUTOOFF (1 << 7)
++
++
++
++
++
++
++#define CPIOC_GPIOGET _IOR(CP210X_IOCTL_BASE, 0, int)
++#define CPIOC_GPIOSET _IOW(CP210X_IOCTL_BASE, 1, int)
++#define CPIOC_GPIOBIC _IOW(CP210X_IOCTL_BASE, 2, int)
++#define CPIOC_GPIOBIS _IOW(CP210X_IOCTL_BASE, 3, int)
++
++#define CPIOC_DEVICERESET _IO(CP210X_IOCTL_BASE,4)
++#define CPIOC_PORTCONFGET _IOR(CP210X_IOCTL_BASE, 5, struct cp210x_port_config)
++#define CPIOC_PORTCONFSET _IOW(CP210X_IOCTL_BASE, 6, struct cp210x_port_config)
++
++#define CPIOC_SETVID _IOW(CP210X_IOCTL_BASE,7, int)
++#define CPIOC_SETPID _IOW(CP210X_IOCTL_BASE,8, int)
++#define CPIOC_SETMFG _IOW(CP210X_IOCTL_BASE,9, char *)
++#define CPIOC_SETPRODUCT _IOW(CP210X_IOCTL_BASE,10, char *)
++#define CPIOC_SETSERIAL _IOW(CP210X_IOCTL_BASE,11, char *)
++#define CPIOC_SETDEVVER _IOW(CP210X_IOCTL_BASE,12, int)
++
++/* CP2103 GPIO */
++#define CP_GPIO_0 0x01
++#define CP_GPIO_1 0x02
++#define CP_GPIO_2 0x04
++#define CP_GPIO_3 0x08
++#define CP_GPIO_MASK (CP_GPIO_0|CP_GPIO_1|CP_GPIO_2|CP_GPIO_3)
++
++
++#define CP210x_MAX_MFG_STRLEN 128
++#define CP210x_MAX_PRODUCT_STRLEN 126
++#define CP210x_MAX_SERIAL_STRLEN 63
++#define CP210x_MAX_MAXPOWER 250
++
++#endif /* _CPIO210X_H */
++