+/**
+ * cptwiddle.c
+ *
+ * Twiddle the leds connected to the cp2103's GPIO_0 and GPIO_1 pins on the
+ * USB device. Twiddle does the following:
+ *
+ * - Saves the current latch and port config settings
+ * - Reconfigures for leds as IO
+ * - Resets the device and reconnects to it
+ * - Twiddles the LEDs
+ * - Restores the original configuration
+ * - Resets the device again so that the original config is immediately active
+ *
+ * Watch out; the tty device is hard-coded.
+ */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+/* CP2103 ioctls */
+#define IOCTL_GPIOGET 0x8000 /* Get gpio bits */
+#define IOCTL_GPIOSET 0x8001 /* Set gpio bits */
+#define IOCTL_GPIOBIC 0x8002 /* Clear specific gpio bit(s) */
+#define IOCTL_GPIOBIS 0x8003 /* Set specific gpio bit(s) */
+
+/* CP210x ioctls principally used during initial device configuration */
+#define IOCTL_DEVICERESET 0x8004 /* Reset the cp210x */
+#define IOCTL_PORTCONFGET 0x8005 /* Get port configuration */
+#define IOCTL_PORTCONFSET 0x8006 /* Set port configuration */
+#define IOCTL_SETVID 0x8007 /* Set vendor id */
+#define IOCTL_SETPID 0x8008 /* Set product id */
+#define IOCTL_SETMFG 0x8009 /* Set manufacturer string */
+#define IOCTL_SETPRODUCT 0x800a /* Set product string */
+#define IOCTL_SETSERIAL 0x800b /* Set serial number string */
+#define IOCTL_SETDEVVER 0x800c /* set device version id */
+/* FIXME: where is IOCTL_SETMFG? */
+
+
+typedef struct {
+ uint16_t mode;
+ uint16_t lowPower;
+ uint16_t latch;
+} cp2103_port_state_t;
+
+typedef struct {
+ cp2103_port_state_t reset;
+ cp2103_port_state_t suspend;
+ uint8_t enhancedFxn;
+} cp2103_port_config_t;
+
+int cpConnect()
+{
+ int ret, ioval;
+ int fd = open("/dev/usb/tts/0", O_RDWR);
+ if (fd < 0) {
+ fprintf(stderr, "cannot open tty\n");
+ return -1;
+ }
+ printf("tty opened\n");
+ return fd;
+}
+
+void cpDisconnect(int fd)
+{
+ if (fd >= 0)
+ close(fd);
+}
+
+int main()
+{
+ int fd;
+ cp2103_port_config_t config;
+ cp2103_port_config_t saveConfig;
+ uint8_t saveGpio;
+ int ret;
+ int i;
+
+ if ((fd = cpConnect()) < 0)
+ return 1;
+
+ /* Read the current port configuration */
+ if ((ret = ioctl(fd, IOCTL_PORTCONFGET, &config))) {
+ fprintf(stderr, "portconfget ioctl failed %d\n", ret);
+ return 1;
+ }
+ memcpy(&saveConfig, &config, sizeof(config));
+ printf("port config received\n");
+
+ /* Read the current gpio latches */
+ if ((ret = ioctl(fd, IOCTL_GPIOGET, &saveGpio))) {
+ fprintf(stderr, "gpioget ioctl failed %d\n", ret);
+ return 1;
+ }
+ printf("saved gpio latches 0x%02x\n", saveGpio);
+
+ /* Set the current port configuration; set GPIO_0 and GPIO_1 as outputs */
+ config.reset.mode &= ~0x0300;
+ config.suspend.mode &= ~0x0300;
+ config.reset.latch |= 0x0300;
+ config.enhancedFxn &= ~0x03;
+ if ((ret = ioctl(fd, IOCTL_PORTCONFSET, &config))) {
+ fprintf(stderr, "portconfset ioctl failed %d\n", ret);
+ return 1;
+ }
+ printf("port config altered\n");
+
+ /* Reset the part */
+ if ((ret = ioctl(fd, IOCTL_DEVICERESET, 0))) {
+ fprintf(stderr, "device reset ioctl failed %d\n", ret);
+ return 1;
+ }
+ printf("device reset\n");
+
+ /* Disconnect then reconnect */
+ cpDisconnect(fd);
+ printf("disconnected\n");
+ for (i = 0; i < 10; i++) {
+ sleep(1);
+ if ((fd = cpConnect()) >= 0)
+ break;
+ }
+ if (i == 100) {
+ printf("failed to reconnect\n");
+ return 1;
+ }
+ printf("reconnected\n");
+
+ /* Now, twiddle some bits */
+ for (i = 0; i < 8; i++) {
+ uint8_t leds = i & 0x03;
+ if ((ret = ioctl(fd, IOCTL_GPIOSET, leds))) {
+ fprintf(stderr, "gpio set ioctl failed %d\n", ret);
+ return 1;
+ }
+ printf("set leds %u\n", leds);
+ sleep(1);
+ }
+
+ /* Restore the original latches */
+ if ((ret = ioctl(fd, IOCTL_GPIOSET, saveGpio))) {
+ fprintf(stderr, "gpio set ioctl failed %d\n", ret);
+ return 1;
+ }
+ printf("gpio latches restored\n");
+
+ /* Return the original configuration */
+ if ((ret = ioctl(fd, IOCTL_PORTCONFSET, &saveConfig))) {
+ fprintf(stderr, "portconfset ioctl failed %d\n", ret);
+ return 1;
+ }
+ printf("port config restored\n");
+
+ /* Reset the part again */
+ if ((ret = ioctl(fd, IOCTL_DEVICERESET, 0))) {
+ fprintf(stderr, "device reset ioctl failed %d\n", ret);
+ return 1;
+ }
+ printf("device reset again\n");
+
+ cpDisconnect(fd);
+ return 0;
+}