summaryrefslogtreecommitdiffstats
path: root/master/motors
diff options
context:
space:
mode:
authorroot <root@lamia.panaceas.james.local>2015-09-27 11:51:12 +0100
committerroot <root@lamia.panaceas.james.local>2015-09-27 11:51:12 +0100
commitfb709653ff255ef72b3fb3ab10137e104a52750f (patch)
treef2b73897244c8d7ee397a36649512322a6d1675a /master/motors
parent83ded88a16a3bbc2e9a50902b0b9728e4e50aad3 (diff)
downloadtrunk-47048-pq-fb709653ff255ef72b3fb3ab10137e104a52750f.tar.gz
trunk-47048-pq-fb709653ff255ef72b3fb3ab10137e104a52750f.tar.bz2
trunk-47048-pq-fb709653ff255ef72b3fb3ab10137e104a52750f.zip
cleanup
Diffstat (limited to 'master/motors')
-rw-r--r--master/motors1236
1 files changed, 1236 insertions, 0 deletions
diff --git a/master/motors b/master/motors
new file mode 100644
index 0000000..33f4a7c
--- /dev/null
+++ b/master/motors
@@ -0,0 +1,1236 @@
+diff --git a/feeds/packages/multimedia/mjpg-streamer/Makefile b/feeds/packages/multimedia/mjpg-streamer/Makefile
+index e1e0e20..ff98b4d 100644
+--- a/feeds/packages/multimedia/mjpg-streamer/Makefile
++++ b/feeds/packages/multimedia/mjpg-streamer/Makefile
+@@ -88,6 +88,7 @@ ifeq ($(CONFIG_MJPG_STREAMER_INPUT_FILE),y)
+ endif
+ ifeq ($(CONFIG_MJPG_STREAMER_INPUT_UVC),y)
+ $(CP) $(PKG_BUILD_DIR)/input_uvc.so $(1)/usr/lib
++ $(CP) $(PKG_BUILD_DIR)/input_motors.so $(1)/usr/lib
+ endif
+ ifeq ($(CONFIG_MJPG_STREAMER_INPUT_TESTPICTURE),y)
+ $(CP) $(PKG_BUILD_DIR)/input_testpicture.so $(1)/usr/lib
+diff --git a/feeds/packages/multimedia/mjpg-streamer/files/mjpg-streamer.init b/feeds/packages/multimedia/mjpg-streamer/files/mjpg-streamer.init
+index 06630d4..ea83303 100644
+--- a/feeds/packages/multimedia/mjpg-streamer/files/mjpg-streamer.init
++++ b/feeds/packages/multimedia/mjpg-streamer/files/mjpg-streamer.init
+@@ -83,7 +83,7 @@ start_instance() {
+ fi
+
+ procd_open_instance
+- procd_set_param command "$PROG" --input "$input_arg" --output "$output_arg"
++ procd_set_param command "$PROG" --input "$input_arg" --input "input_motors.so" --output "$output_arg"
+ procd_close_instance
+ }
+
+diff --git a/feeds/packages/multimedia/mjpg-streamer/patches/999-motors.patch b/feeds/packages/multimedia/mjpg-streamer/patches/999-motors.patch
+new file mode 100644
+index 0000000..5ffdc58
+--- /dev/null
++++ b/feeds/packages/multimedia/mjpg-streamer/patches/999-motors.patch
+@@ -0,0 +1,906 @@
++Index: bar/Makefile
++===================================================================
++--- bar.orig/Makefile
+++++ bar/Makefile
++@@ -33,6 +33,7 @@ APP_BINARY = mjpg_streamer
++
++ # define the names and targets of the plugins
++ PLUGINS = input_uvc.so
+++PLUGINS += input_motors.so
++ PLUGINS += output_file.so
++ #PLUGINS += output_udp.so
++ PLUGINS += output_http.so
++@@ -71,6 +72,9 @@ input_testpicture.so: mjpg_streamer.h ut
++ make -C plugins/input_testpicture all
++ cp plugins/input_testpicture/input_testpicture.so .
++
+++input_motors.so: mjpg_streamer.h utils.h
+++ make -C plugins/input_motors
+++ cp plugins/input_motors/input_motors.so .
++
++ ifeq ($(USE_LIBV4L2),true)
++ input_uvc.so: mjpg_streamer.h utils.h
++Index: bar/plugins/input_motors/input_motors.c
++===================================================================
++--- /dev/null
+++++ bar/plugins/input_motors/input_motors.c
++@@ -0,0 +1,708 @@
+++/*******************************************************************************
+++# Linux-UVC streaming input-plugin for MJPG-streamer #
+++# #
+++# This package work with the Logitech UVC based webcams with the mjpeg feature #
+++# #
+++# Copyright (C) 2005 2006 Laurent Pinchart && Michel Xhaard #
+++# 2007 Lucas van Staden #
+++# 2007 Tom Stöveken #
+++# #
+++# 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. #
+++# #
+++# 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, write to the Free Software #
+++# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #
+++# #
+++*******************************************************************************/
+++
+++#include <stdio.h>
+++#include <stdlib.h>
+++#include <unistd.h>
+++#include <string.h>
+++#include <fcntl.h>
+++#include <sys/ioctl.h>
+++#include <errno.h>
+++#include <signal.h>
+++#include <sys/socket.h>
+++#include <arpa/inet.h>
+++#include <sys/types.h>
+++#include <sys/stat.h>
+++#include <getopt.h>
+++#include <pthread.h>
+++#include <syslog.h>
+++
+++#include "../../utils.h"
+++#include "../../mjpg_streamer.h"
+++
+++#define INPUT_PLUGIN_NAME "KKMoon motors control"
+++
+++#define MIN_RES 5
+++
+++#if 0
+++#undef DBG
+++#define DBG(a...) do { fprintf(stderr,a); } while (0)
+++#endif
+++
+++
+++#define V_MIN -175
+++#define V_MAX 455
+++
+++#define H_MIN -1040
+++#define H_MAX 1030
+++
+++#define H_STEPS (1+(H_MAX)-(H_MIN))
+++#define V_STEPS (1+(V_MAX)-(V_MIN))
+++
+++
+++
+++typedef struct input_motors
+++{
+++ int fd;
+++ char *device;
+++ int min_res;
+++} input_motors;
+++
+++/* private functions and variables to this plugin */
+++static pthread_t worker;
+++static pthread_mutex_t motor_mutex = PTHREAD_MUTEX_INITIALIZER;
+++static pthread_mutex_t worker_mutex = PTHREAD_MUTEX_INITIALIZER;
+++static pthread_cond_t worker_cond = PTHREAD_COND_INITIALIZER;
+++static input_motors *this;
+++static globals *pglobal;
+++static int plugin_number;
+++
+++
+++static volatile int worker_pan, worker_tilt;
+++
+++static void
+++motor_cmd (int fd, char m, size_t n)
+++{
+++ static char buf[8192];
+++ size_t l;
+++
+++ DBG ("motor: %c for %d\n", m, (int) n);
+++
+++ while (n)
+++ {
+++ l = (n > sizeof (buf)) ? sizeof (buf) : n;
+++ pthread_mutex_lock (&motor_mutex);
+++ memset (buf, m, l);
+++ write (fd, buf, l);
+++ pthread_mutex_unlock (&motor_mutex);
+++ n -= l;
+++ }
+++}
+++
+++static int pan_valid, pan;
+++
+++static void
+++pan_move (int fd, int m)
+++{
+++ DBG ("pan_move: %d\n", m);
+++ if (m < 0)
+++ motor_cmd (fd, 'L', -m);
+++ else
+++ motor_cmd (fd, 'R', m);
+++}
+++
+++
+++static void
+++pan_abs (int fd, int p)
+++{
+++ DBG ("pan_abs: pan_valid=%d pan=%d requested=%d\n", pan_valid, pan, p);
+++
+++ if (!pan_valid)
+++ {
+++ pan_move (fd, -H_STEPS);
+++ pan_valid = 1;
+++ pan = H_MIN;
+++ }
+++
+++ if (p < H_MIN)
+++ p = H_MIN;
+++ if (p > H_MAX)
+++ p = H_MAX;
+++
+++ pan_move (fd, p - pan);
+++
+++ pan = p;
+++}
+++
+++static void
+++pan_rel (int fd, int m)
+++{
+++ DBG ("pan_rel: pan_valid=%d pan=%d requested=%d\n", pan_valid, pan, m);
+++ if (pan_valid)
+++ {
+++ pan_abs (fd, pan + m);
+++ }
+++ else
+++ {
+++ pan_move (fd, m);
+++ }
+++}
+++
+++
+++
+++static int tilt_valid, tilt;
+++
+++static void
+++tilt_move (int fd, int m)
+++{
+++ DBG ("tilt_move: %d\n", m);
+++ if (m < 0)
+++ motor_cmd (fd, 'D', -m);
+++ else
+++ motor_cmd (fd, 'U', m);
+++}
+++
+++
+++static void
+++tilt_abs (int fd, int p)
+++{
+++ DBG ("tilt_abs tilt_valid=%d tilt=%d requested=%d\n", tilt_valid, tilt, p);
+++ if (!tilt_valid)
+++ {
+++ tilt_move (fd, -V_STEPS);
+++ tilt_valid = 1;
+++ tilt = V_MIN;
+++ }
+++
+++ if (p < V_MIN)
+++ p = V_MIN;
+++ if (p > V_MAX)
+++ p = V_MAX;
+++
+++ tilt_move (fd, p - tilt);
+++
+++ tilt = p;
+++}
+++
+++static void
+++tilt_rel (int fd, int m)
+++{
+++ DBG ("tilt_rel tilt_valid=%d tilt=%d requested=%d\n", tilt_valid, tilt, m);
+++ if (tilt_valid)
+++ {
+++ tilt_abs (fd, tilt + m);
+++ }
+++ else
+++ {
+++ tilt_move (fd, m);
+++ }
+++}
+++
+++
+++
+++
+++static void
+++help (void)
+++{
+++ fprintf (stderr,
+++ " ---------------------------------------------------------------\n"
+++ " Help for input plugin..: " INPUT_PLUGIN_NAME "\n"
+++ " ---------------------------------------------------------------\n"
+++ " The following parameters can be passed to this plugin:\n\n"
+++ " [-d | --device ]...: video device to open (your camera)\n"
+++ " [-m | --min ]......: set the minimum step size in phases (defalt 5)\n");
+++}
+++
+++
+++
+++
+++static void
+++worker_cleanup (void *arg)
+++{
+++ static unsigned char first_run = 1;
+++
+++ if (!first_run)
+++ {
+++ DBG ("already cleaned up ressources\n");
+++ return;
+++ }
+++
+++ first_run = 0;
+++}
+++
+++
+++
+++
+++static void *
+++worker_thread (void *arg)
+++{
+++ struct timespec ts = { 0 };
+++ int err;
+++
+++
+++ /* set cleanup handler to cleanup allocated ressources */
+++ pthread_cleanup_push (worker_cleanup, NULL);
+++
+++ while (!pglobal->stop)
+++ {
+++
+++ clock_gettime (CLOCK_MONOTONIC, &ts);
+++
+++ ts.tv_sec += 1;
+++
+++ pthread_mutex_lock (&worker_mutex);
+++ pthread_cond_timedwait (&worker_cond, &worker_mutex, &ts);
+++ pthread_mutex_unlock (&worker_mutex);
+++ while (worker_pan || worker_tilt)
+++ {
+++ if (worker_pan)
+++ pan_rel (this->fd, worker_pan);
+++ if (worker_tilt)
+++ tilt_rel (this->fd, worker_tilt);
+++ }
+++
+++ pthread_cond_broadcast (&pglobal->in[plugin_number].db_update); //this keeps the output stream alive
+++ DBG ("spin loop\n");
+++ }
+++
+++ DBG ("leaving input thread, calling cleanup function now\n");
+++ pthread_cleanup_pop (1);
+++
+++ return NULL;
+++}
+++
+++
+++void
+++add_control (int plugin_number, control c)
+++{
+++ if (!pglobal->in[plugin_number].in_parameters)
+++ {
+++ pglobal->in[plugin_number].in_parameters =
+++ (control *) calloc (1, sizeof (control));
+++ }
+++ else
+++ {
+++ pglobal->in[plugin_number].in_parameters =
+++ (control *) realloc (pglobal->in[plugin_number].in_parameters,
+++ (pglobal->in[plugin_number].parametercount +
+++ 1) * sizeof (control));
+++ }
+++
+++ if (pglobal->in[plugin_number].in_parameters == NULL)
+++ {
+++ DBG ("Calloc failed\n");
+++ return;
+++ }
+++
+++ pglobal->in[plugin_number].in_parameters[pglobal->in[plugin_number].
+++ parametercount] = c;
+++
+++ pglobal->in[plugin_number].parametercount++;
+++
+++}
+++
+++
+++
+++static void
+++add_btn (int plugin_number, unsigned int id, char *name)
+++{
+++
+++ control btn;
+++
+++ btn.group = IN_CMD_GENERIC;
+++ btn.menuitems = NULL;
+++ btn.value = 0.0;
+++ btn.class_id = 0;
+++
+++ btn.ctrl.id = id;
+++ btn.ctrl.type = V4L2_CTRL_TYPE_BUTTON;
+++ strcpy ((char *) btn.ctrl.name, name);
+++ btn.ctrl.minimum = 0;
+++ btn.ctrl.maximum = 1;
+++ btn.ctrl.step = 1;
+++ btn.ctrl.default_value = 0;
+++ btn.ctrl.flags = V4L2_CTRL_FLAG_VOLATILE;
+++
+++ add_control (plugin_number, btn);
+++
+++}
+++
+++static void
+++add_bool (int plugin_number, unsigned int id, char *name)
+++{
+++
+++ control btn;
+++
+++ btn.group = IN_CMD_GENERIC;
+++ btn.menuitems = NULL;
+++ btn.value = 0.0;
+++ btn.class_id = 0;
+++
+++ btn.ctrl.id = id;
+++ btn.ctrl.type = V4L2_CTRL_TYPE_BOOLEAN;
+++ strcpy ((char *) btn.ctrl.name, name);
+++ btn.ctrl.minimum = 0;
+++ btn.ctrl.maximum = 1;
+++ btn.ctrl.step = 1;
+++ btn.ctrl.default_value = 0;
+++ btn.ctrl.flags = V4L2_CTRL_FLAG_VOLATILE;
+++
+++ add_control (plugin_number, btn);
+++
+++}
+++
+++
+++static void
+++add_abs (int plugin_number, unsigned int id, char *name, int max)
+++{
+++
+++ control abs;
+++
+++ abs.group = IN_CMD_GENERIC;
+++ abs.menuitems = NULL;
+++ abs.value = 0xffffff;
+++ abs.class_id = 0;
+++
+++ abs.ctrl.id = id;
+++ abs.ctrl.type = V4L2_CTRL_TYPE_INTEGER;
+++ strcpy ((char *) abs.ctrl.name, name);
+++ abs.ctrl.minimum = -max / 2;
+++ abs.ctrl.maximum = max / 2;
+++ abs.ctrl.step = 1;
+++ abs.ctrl.default_value = 0;
+++ abs.ctrl.flags = V4L2_CTRL_FLAG_VOLATILE | V4L2_CTRL_FLAG_SLIDER;
+++
+++ add_control (plugin_number, abs);
+++
+++}
+++
+++
+++static void
+++add_controls (int plugin_number)
+++{
+++ add_btn (plugin_number, IN_CMD_RESET_PAN_TILT, "Reset");
+++#ifdef USE_BUTTONS
+++ add_btn (plugin_number, IN_CMD_PAN_MINUS, "Pan-");
+++ add_btn (plugin_number, IN_CMD_PAN_PLUS, "Pan+");
+++ add_btn (plugin_number, IN_CMD_TILT_MINUS, "Tilt-");
+++ add_btn (plugin_number, IN_CMD_TILT_PLUS, "Tilt+");
+++#else
+++ add_bool (plugin_number, IN_CMD_PAN_MINUS, "Pan-");
+++ add_bool (plugin_number, IN_CMD_PAN_PLUS, "Pan+");
+++ add_bool (plugin_number, IN_CMD_TILT_MINUS, "Tilt-");
+++ add_bool (plugin_number, IN_CMD_TILT_PLUS, "Tilt+");
+++#endif
+++ add_abs (plugin_number, IN_CMD_PAN_SET, "Pan", H_STEPS);
+++ add_abs (plugin_number, IN_CMD_TILT_SET, "Tilt", V_STEPS);
+++
+++}
+++
+++
+++
+++/*** plugin interface functions ***/
+++
+++
+++int
+++input_init (input_parameter * param, int id)
+++{
+++ int i;
+++ char *dev = "/dev/motors";
+++
+++ plugin_number = id;
+++
+++ if (pthread_mutex_init (&motor_mutex, NULL) != 0)
+++ {
+++ IPRINT ("could not initialize mutex variable\n");
+++ exit (EXIT_FAILURE);
+++ }
+++
+++ if (pthread_mutex_init (&worker_mutex, NULL) != 0)
+++ {
+++ IPRINT ("could not initialize mutex variable\n");
+++ exit (EXIT_FAILURE);
+++ }
+++
+++
+++ {
+++ pthread_condattr_t attr;
+++ pthread_condattr_init (&attr);
+++ pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
+++
+++ if (pthread_cond_init (&worker_cond, &attr) != 0)
+++ {
+++ IPRINT ("could not initialize cond variable\n");
+++ exit (EXIT_FAILURE);
+++ }
+++
+++ }
+++
+++
+++
+++ /* keep a pointer to the global variables */
+++ pglobal = param->global;
+++
+++ /* allocate webcam datastructure */
+++ this = malloc (sizeof (struct input_motors));
+++ if (this == NULL)
+++ {
+++ IPRINT ("not enough memory for videoIn\n");
+++ exit (EXIT_FAILURE);
+++ }
+++ memset (this, 0, sizeof (struct input_motors));
+++ this->min_res = MIN_RES;
+++
+++ /* display the parsed values */
+++ IPRINT ("Using motors device.: %s\n", dev);
+++
+++ param->argv[0] = INPUT_PLUGIN_NAME;
+++ asprintf (&param->global->in[id].name, "%s", INPUT_PLUGIN_NAME);
+++
+++ /* show all parameters for DBG purposes */
+++ for (i = 0; i < param->argc; i++)
+++ {
+++ DBG ("argv[%d]=%s\n", i, param->argv[i]);
+++ }
+++
+++ /* parse the parameters */
+++ reset_getopt ();
+++ while (1)
+++ {
+++ int option_index = 0, c = 0;
+++ static struct option long_options[] = {
+++ {"h", no_argument, 0, 0},
+++ {"help", no_argument, 0, 0},
+++ {"d", required_argument, 0, 0},
+++ {"device", required_argument, 0, 0},
+++ {"m", required_argument, 0, 0},
+++ {"min", required_argument, 0, 0},
+++ {0, 0, 0, 0}
+++ };
+++
+++ /* parsing all parameters according to the list above is sufficent */
+++ c =
+++ getopt_long_only (param->argc, param->argv, "", long_options,
+++ &option_index);
+++
+++ /* no more options to parse */
+++ if (c == -1)
+++ break;
+++
+++ /* unrecognized option */
+++ if (c == '?')
+++ {
+++ help ();
+++ return 1;
+++ }
+++
+++ /* dispatch the given options */
+++ switch (option_index)
+++ {
+++ /* h, help */
+++ case 0:
+++ case 1:
+++ DBG ("case 0,1\n");
+++ help ();
+++ return 1;
+++ break;
+++
+++ /* d, device */
+++ case 2:
+++ case 3:
+++ DBG ("case 2,3\n");
+++ dev = strdup (optarg);
+++ break;
+++
+++ case 4:
+++ case 5:
+++ DBG ("case 4,5\n");
+++ this->min_res = atoi (optarg);
+++ break;
+++
+++ default:
+++ DBG ("default case\n");
+++ help ();
+++ return 1;
+++ }
+++ }
+++
+++ asprintf (&this->device, "%s", dev);
+++
+++ if ((this->fd = open (this->device, O_RDWR)) == -1)
+++ {
+++ perror ("ERROR opening motor interface");
+++ return -1;
+++ }
+++
+++
+++ add_controls (plugin_number);
+++
+++ return 0;
+++}
+++
+++/******************************************************************************
+++Description.: Stops the execution of worker thread
+++Input Value.: -
+++Return Value: always 0
+++******************************************************************************/
+++int
+++input_stop (void)
+++{
+++ DBG ("will cancel input thread\n");
+++ pthread_cancel (worker);
+++
+++ return 0;
+++}
+++
+++/******************************************************************************
+++Description.: spins of a worker thread
+++Input Value.: -
+++Return Value: always 0
+++******************************************************************************/
+++int
+++input_run (void)
+++{
+++
+++ pthread_create (&worker, 0, worker_thread, NULL);
+++ pthread_detach (worker);
+++
+++ return 0;
+++}
+++
+++/******************************************************************************
+++Description.: process commands, allows to set certain runtime configurations
+++ and settings like pan/tilt, colors, saturation etc.
+++Input Value.: * cmd specifies the command, a complete list is maintained in
+++ the file "input.h"
+++ * value is used for commands that make use of a parameter.
+++Return Value: depends in the command, for most cases 0 means no errors and
+++ -1 signals an error. This is just rule of thumb, not more!
+++******************************************************************************/
+++int
+++input_cmd_old (in_cmd_type cmd, int value)
+++{
+++ int res = 0;
+++
+++
+++ switch (cmd)
+++ {
+++ case IN_CMD_HELLO:
+++ fprintf (stderr, "Hello from input plugin\n");
+++ break;
+++
+++ case IN_CMD_RESET_PAN_TILT:
+++ case IN_CMD_RESET_PAN_TILT_NO_MUTEX:
+++ DBG ("about to set pan/tilt to default position\n");
+++
+++ pan_abs (this->fd, 0);
+++ tilt_abs (this->fd, 0);
+++
+++ break;
+++
+++ case IN_CMD_PAN_SET:
+++ DBG ("set pan to %d steps\n", value);
+++
+++ pan_abs (this->fd, value);
+++
+++ res = value;
+++ break;
+++
+++ case IN_CMD_PAN_PLUS:
+++ DBG ("pan + %d\n", value);
+++#ifdef USE_BUTTONS
+++ pan_rel (this->fd, this->min_res);
+++ res = this->min_res;
+++#else
+++ worker_pan = value ? this->min_res : 0;
+++ pthread_cond_broadcast (&worker_cond);
+++ res = value;
+++#endif
+++ break;
+++
+++ case IN_CMD_PAN_MINUS:
+++ DBG ("pan - %d\n", value);
+++#ifdef USE_BUTTONS
+++ pan_rel (this->fd, -this->min_res);
+++ res = this->min_res;
+++#else
+++ worker_pan = value ? -this->min_res : 0;
+++ pthread_cond_broadcast (&worker_cond);
+++ res = value;
+++#endif
+++
+++ break;
+++
+++ case IN_CMD_TILT_SET:
+++ DBG ("set tilt to %d degrees\n", value);
+++
+++ tilt_abs (this->fd, value);
+++ res = value;
+++ break;
+++
+++ case IN_CMD_TILT_PLUS:
+++ DBG ("tilt + %d\n", value);
+++#ifdef USE_BUTTONS
+++ tilt_rel (this->fd, this->min_res);
+++
+++ res = this->min_res;
+++#else
+++ worker_tilt = value ? this->min_res : 0;
+++ pthread_cond_broadcast (&worker_cond);
+++ res = value;
+++#endif
+++
+++ break;
+++
+++ case IN_CMD_TILT_MINUS:
+++ DBG ("tilt - %d\n", value);
+++
+++#ifdef USE_BUTTONS
+++ tilt_rel (this->fd, -this->min_res);
+++
+++ res = this->min_res;
+++#else
+++ worker_tilt = value ? -this->min_res : 0;
+++ pthread_cond_broadcast (&worker_cond);
+++ res = value;
+++#endif
+++
+++ break;
+++
+++ default:
+++ DBG ("nothing matched\n");
+++ res = -1;
+++ }
+++
+++
+++ return res;
+++}
+++
+++
+++
+++int
+++input_cmd (int plugin_number, unsigned int control_id, unsigned int group,
+++ int value, char *value_string)
+++{
+++ int ret = -1;
+++ DBG ("Requested cmd (id: %d) for the %d plugin. Group: %d value: %d\n",
+++ control_id, plugin_number, group, value);
+++
+++ if (group != IN_CMD_GENERIC)
+++ return -1;
+++
+++ switch (control_id)
+++ {
+++ case IN_CMD_PAN_MINUS:
+++ case IN_CMD_PAN_PLUS:
+++ case IN_CMD_TILT_MINUS:
+++ case IN_CMD_TILT_PLUS:
+++ case IN_CMD_TILT_SET:
+++ case IN_CMD_PAN_SET:
+++ case IN_CMD_RESET_PAN_TILT:
+++ ret = input_cmd_old (control_id, value);
+++ break;
+++ }
+++
+++ return ret;
+++}
++Index: bar/plugins/input_motors/Makefile
++===================================================================
++--- /dev/null
+++++ bar/plugins/input_motors/Makefile
++@@ -0,0 +1,24 @@
+++###############################################################
+++#
+++# Purpose: Makefile for "M-JPEG Streamer"
+++# Author.: Tom Stoeveken (TST)
+++# Version: 0.3
+++# License: GPL
+++#
+++###############################################################
+++
+++CC = gcc
+++
+++OTHER_HEADERS = ../../mjpg_streamer.h ../../utils.h ../output.h ../input.h
+++
+++CFLAGS += -O2 -DLINUX -D_GNU_SOURCE -Wall -shared -fPIC
+++#CFLAGS += -DDEBUG
+++
+++all: input_motors.so
+++
+++clean:
+++ rm -f *.a *.o core *~ *.so *.lo
+++
+++input_motors.so: $(OTHER_HEADERS)
+++ $(CC) $(CFLAGS) $(LFLAGS) -o $@ input_motors.c
+++
++Index: bar/www/index.html
++===================================================================
++--- bar.orig/www/index.html
+++++ bar/www/index.html
++@@ -3,53 +3,87 @@
++ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
++ <head>
++ <title>MJPG-streamer</title>
++- <meta http-equiv="content-type" content="text/html; charset=iso-8859-1" />
++- <link rel="stylesheet" href="style.css" type="text/css" />
+++ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+++
+++ <link rel="stylesheet" href="index.css" type="text/css" />
+++
++ <!--[if IE 6]>
++ <link rel="stylesheet" href="fix.css" type="text/css" />
++ <![endif]-->
++ </head>
++-
+++
++ <body>
++- <div id="sidebar">
++- <h1>MJPG-Streamer Demo Pages</h1>
++- <h2>a ressource friendly streaming application</h2>
++-
++- <div id="menu">
++- <a class="active" href="index.html">Home</a>
++- <a href="static.html">Static</a>
++- <a href="stream.html">Stream</a>
++- <a href="java.html">Java</a>
++- <a href="javascript.html">Javascript</a>
++- <a href="videolan.html">VideoLAN</a>
++- <a target="_blank" onClick="window.open(this.href, '_blank'); return false;" href="control.html">Control</a>
++- <a target="_blank" onClick="window.open(this.href, '_blank'); return false;" href="control_old.html">Control old</a>
++- </div>
++-
++- <h3>Version info:</h3>
++- <p>v0.1 (Okt 22, 2007)</p>
++- </div>
++-
++- <div id="content">
++- <h1>About</h1>
++- <h2>Details about the M-JPEG streamer</h2>
++-
++- <h3>Congratulations</h3>
++- <p>You sucessfully managed to install this streaming webserver. If you can see this page, you can also access the stream of JPGs, which can originate from your webcam for example. This installation consists of these example pages and you may customize the look and content.</p>
++-
++- <img src="example.jpg" width="512" height="160" alt="just an image" />
++- <p>The reason for developing this software was the need of a simple and ressource friendly streaming application for Linux-UVC compatible webcams. The predecessor <i>uvc-streamer</i> is working well, but i wanted to implement a few more ideas. For instance, plugins can be used to process the images. One input plugin copies images to a global variable, multiple output plugins can access those images. For example this webpage is served by the <i>output_http.so</i> plugin.</p>
++-
++- <a href="static.html"><img src="/?action=snapshot" width="170" height="128" alt="static image example" /></a>
++- <p>The image displayed here was grabbed by the input plugin. The HTTP request contains the GET parameters <i>action=snapshot</i>. This requests one single picture from the image-input. To display another example, just click on the picture.</p>
++
++- <h3>About the examples</h3>
++- <p>To view the stream with any browser you may try the <i>javascript</i> or <i>java</i> subpages. Firefox is able to display the M-JPEG-stream directly.</p>
+++ <p id="streamwrap" class="xform-p">
+++ <img id="streamimage" class="x-rotated-180" src="/?action=stream" />
+++ </p>
+++
+++ <script type="text/javascript">
+++
+++ function send_button(command,value) {
+++ action_zone.location='http://10.32.48.227:8080/?action=command_ng&dest=0&plugin=1&id='+command+'&group=0&value='+value;
+++ }
+++
+++ function up_onmousedown()
+++ {
+++ send_button(9,1);
+++ }
+++
+++ function up_onmouseup()
+++ {
+++ send_button(9,0);
+++ }
+++
+++
+++
+++ function down_onmousedown()
+++ {
+++ send_button(10,1);
+++ }
+++
+++ function down_onmouseup()
+++ {
+++ send_button(10,0);
+++ }
+++
+++
+++
+++
+++ function left_onmousedown()
+++ {
+++ send_button(7,1);
+++ }
+++
+++ function left_onmouseup()
+++ {
+++ send_button(7,0);
+++ }
+++
+++
+++ function right_onmousedown()
+++ {
+++ send_button(6,1);
+++ }
+++
+++ function right_onmouseup()
+++ {
+++ send_button(6,0);
+++ }
+++
+++ </script>
+++
+++ <div id="tabs">
+++ <ul id="ul_tabs"></ul>
+++ </div>
+++
+++ <h2>
+++ <span onmouseup="left_onmouseup()" onmousedown="left_onmousedown()" style="border:solid 1px red">←</span>
+++ <span onmouseup="up_onmouseup()" onmousedown="up_onmousedown()" style="border:solid 1px red">↑</span>
+++ <span onmouseup="down_onmouseup()" onmousedown="down_onmousedown()" style="border:solid 1px red">↓</span>
+++ <span onmouseup="right_onmouseup()" onmousedown="right_onmousedown()" style="border:solid 1px red">→</span>
+++ </h2>
++
++- <h3>About this server</h3>
++- <p>This server is running a software written for the MJPG-streamer project. The MJPG-streamer developers can not be made responsible for installations of this software.</p>
+++ <iframe name="action_zone" style="display:none" bgcolor='#d8d8d8'></iframe>
++
++- <p>&copy; The <a href="http://mjpg-streamer.sf.net">MJPG-streamer team</a> | Design by <a href="http://andreasviklund.com">Andreas Viklund</a></p>
++- </div>
++ </body>
++ </html>
++Index: bar/www/index.html
++===================================================================
++--- /dev/null
+++++ bar/www/index.css
++@@ -0,0 +1,5 @@
+++img.x-rotated-180 {
+++ -moz-transform: rotate(180deg);
+++ -webkit-transform: rotate(180deg);
+++}
+++
+diff --git a/target/linux/ramips/patches-3.18/9999-kkmoon-motors.patch b/target/linux/ramips/patches-3.18/9999-kkmoon-motors.patch
+new file mode 100644
+index 0000000..2266282
+--- /dev/null
++++ b/target/linux/ramips/patches-3.18/9999-kkmoon-motors.patch
+@@ -0,0 +1,284 @@
++Index: linux-3.18.21/drivers/misc/Kconfig
++===================================================================
++--- linux-3.18.21.orig/drivers/misc/Kconfig
+++++ linux-3.18.21/drivers/misc/Kconfig
++@@ -515,6 +515,13 @@ config VEXPRESS_SYSCFG
++ bus. System Configuration interface is one of the possible means
++ of generating transactions on this bus.
++
+++config KKMOON_MOTORS
+++ tristate "kkmoon motor support"
+++ depends on GPIOLIB
+++ default m
+++ help
+++ kkmoon motors
+++
++ source "drivers/misc/c2port/Kconfig"
++ source "drivers/misc/eeprom/Kconfig"
++ source "drivers/misc/cb710/Kconfig"
++Index: linux-3.18.21/drivers/misc/Makefile
++===================================================================
++--- linux-3.18.21.orig/drivers/misc/Makefile
+++++ linux-3.18.21/drivers/misc/Makefile
++@@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE) += genwqe/
++ obj-$(CONFIG_ECHO) += echo/
++ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
++ obj-$(CONFIG_CXL_BASE) += cxl/
+++obj-$(CONFIG_KKMOON_MOTORS) += kkmoon-motors.o
++Index: linux-3.18.21/drivers/misc/kkmoon-motors.c
++===================================================================
++--- /dev/null
+++++ linux-3.18.21/drivers/misc/kkmoon-motors.c
++@@ -0,0 +1,235 @@
+++#include <linux/init.h>
+++#include <linux/module.h>
+++#include <linux/kernel.h>
+++#include <linux/fs.h>
+++#include <linux/miscdevice.h>
+++#include <linux/delay.h>
+++#include <linux/gpio.h>
+++#include <linux/jiffies.h>
+++#include <linux/sched.h>
+++
+++MODULE_LICENSE ("GPL");
+++MODULE_AUTHOR ("James McKenzie");
+++MODULE_DESCRIPTION ("KKMoon motor control");
+++MODULE_VERSION ("0.1");
+++
+++#define GPIO_A0 22
+++#define GPIO_A1 23
+++#define GPIO_A2 24
+++#define GPIO_D 26
+++
+++
+++static int h_phase;
+++static int v_phase;
+++
+++
+++static void
+++latch_addr (int a)
+++{
+++ gpio_set_value (GPIO_A0, ! !(a & 1));
+++ gpio_set_value (GPIO_A1, ! !(a & 2));
+++ gpio_set_value (GPIO_A2, ! !(a & 4));
+++ ndelay (100);
+++}
+++
+++
+++static void
+++latch_off (void)
+++{
+++ int i;
+++ gpio_set_value (GPIO_D, 0);
+++ for (i = 0; i < 8; ++i)
+++ latch_addr (i);
+++}
+++
+++
+++static void
+++latch_set (int a)
+++{
+++ latch_off ();
+++ latch_addr (a);
+++ gpio_set_value (GPIO_D, 1);
+++}
+++
+++static int
+++inc (int p)
+++{
+++ p++;
+++ p %= 4;
+++ return p;
+++}
+++
+++
+++static int
+++dec (int p)
+++{
+++ p += 3;
+++ p %= 4;
+++ return p;
+++}
+++
+++static void
+++turret_left (void)
+++{
+++ latch_set (h_phase+4);
+++ h_phase = dec (h_phase);
+++ latch_set (h_phase+4);
+++}
+++
+++static void
+++turret_right (void)
+++{
+++ latch_set (h_phase+4);
+++ h_phase = inc (h_phase);
+++ latch_set (h_phase+4);
+++}
+++
+++
+++static void
+++turret_down (void)
+++{
+++ latch_set (v_phase);
+++ v_phase = inc (v_phase);
+++ latch_set (v_phase);
+++}
+++
+++
+++
+++static void
+++turrent_up (void)
+++{
+++ latch_set (v_phase);
+++ v_phase = dec (v_phase);
+++ latch_set (v_phase);
+++}
+++
+++void
+++pause (void)
+++{
+++ set_current_state(TASK_UNINTERRUPTIBLE);
+++ schedule_timeout (HZ / 50);
+++}
+++
+++static ssize_t
+++motors_write (struct file *file, const char __user * data, size_t count,
+++ loff_t * ppos)
+++{
+++ char c;
+++ size_t red = 0;
+++
+++ while (count--)
+++ {
+++
+++#if 1
+++ if (copy_from_user (&c, data++, 1))
+++ return EFAULT;
+++#else
+++ printk("cfu=%d\n",(int) copy_from_user (&c, data++, 1));
+++#endif
+++
+++ switch (c)
+++ {
+++ case 'U':
+++ turrent_up ();
+++ pause ();
+++ break;
+++ case 'D':
+++ turret_down ();
+++ pause ();
+++ break;
+++ case 'L':
+++ turret_left ();
+++ pause ();
+++ break;
+++ case 'R':
+++ turret_right ();
+++ pause ();
+++ break;
+++
+++ }
+++
+++
+++ red++;
+++
+++ }
+++
+++ latch_off ();
+++
+++ *ppos = red;
+++
+++ return red;
+++}
+++
+++
+++static const struct file_operations motors_fops = {
+++ .owner = THIS_MODULE,
+++ .write = motors_write,
+++};
+++
+++
+++static struct miscdevice motors_dev = {
+++ MISC_DYNAMIC_MINOR,
+++ "motors",
+++ &motors_fops
+++};
+++
+++
+++
+++
+++
+++
+++
+++
+++static int __init
+++motors_init (void)
+++{
+++ int ret;
+++ printk (KERN_INFO "KKMOON_MOTOR: Initializing\n");
+++
+++ ret = misc_register (&motors_dev);
+++ if (ret)
+++ return ret;
+++
+++
+++ gpio_request (GPIO_A0, "sysfs");
+++ gpio_request (GPIO_A1, "sysfs");
+++ gpio_request (GPIO_A2, "sysfs");
+++ gpio_request (GPIO_D, "sysfs");
+++
+++ gpio_export (GPIO_A0, false);
+++ gpio_export (GPIO_A1, false);
+++ gpio_export (GPIO_A2, false);
+++ gpio_export (GPIO_D, false);
+++
+++ gpio_direction_output (GPIO_A0, 0);
+++ gpio_direction_output (GPIO_A1, 0);
+++ gpio_direction_output (GPIO_A2, 0);
+++ gpio_direction_output (GPIO_D, 0);
+++
+++
+++ latch_off ();
+++
+++ return 0;
+++}
+++
+++static void __exit
+++motors_exit (void)
+++{
+++
+++ latch_off ();
+++
+++ gpio_unexport (GPIO_D);
+++ gpio_unexport (GPIO_A2);
+++ gpio_unexport (GPIO_A1);
+++ gpio_unexport (GPIO_A0);
+++
+++ gpio_free (GPIO_D);
+++ gpio_free (GPIO_A2);
+++ gpio_free (GPIO_A1);
+++ gpio_free (GPIO_A0);
+++
+++ misc_deregister (&motors_dev);
+++}
+++
+++module_init (motors_init);
+++module_exit (motors_exit);
++Index: linux-3.18.21/drivers/pinctrl/pinctrl-rt2880.c
++===================================================================
++--- linux-3.18.21.orig/drivers/pinctrl/pinctrl-rt2880.c
+++++ linux-3.18.21/drivers/pinctrl/pinctrl-rt2880.c
++@@ -372,6 +372,12 @@ static int rt2880_pinmux_pins(struct rt2
++ /* pin 0 is always a gpio */
++ p->gpio[0] = 1;
++
+++ /*ditto pins 22,23,24,and 26 as we don't have a driver to represent the phy*/
+++ p->gpio[22] = 1;
+++ p->gpio[23] = 1;
+++ p->gpio[24] = 1;
+++ p->gpio[26] = 1;
+++
++ /* set the pads */
++ for (i = 0; i < p->max_pins; i++) {
++ /* strlen("ioXY") + 1 = 5 */
+diff --git a/target/linux/ramips/rt305x/config-3.18 b/target/linux/ramips/rt305x/config-3.18
+index 9c03767..20b69ed 100644
+--- a/target/linux/ramips/rt305x/config-3.18
++++ b/target/linux/ramips/rt305x/config-3.18
+@@ -169,3 +169,4 @@ CONFIG_USB_SUPPORT=y
+ CONFIG_USE_OF=y
+ CONFIG_WATCHDOG_CORE=y
+ CONFIG_ZONE_DMA_FLAG=0
++CONFIG_KKMOON_MOTORS=y