diff --git a/50-mustang.rules b/50-mustang.rules index 18b3576..7b1a0b5 100644 --- a/50-mustang.rules +++ b/50-mustang.rules @@ -1,11 +1,7 @@ -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0004", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0005", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0006", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0007", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0010", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0011", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0012", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0013", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0014", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0015", GROUP="plugdev" -SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0016", GROUP="plugdev" +# Mustang III (original) +ACTION=="add|change", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0005", GROUP="plugdev", RUN+="/bin/bash -c '/bin/echo /usr/local/bin/mustang_bridge_start | /usr/bin/at now'" +ACTION=="remove", ENV{ID_VENDOR_ID}=="1ed8", ENV{ID_MODEL_ID}=="0005", ENV{DEVTYPE}=="usb_device", RUN+="/usr/local/bin/mustang_bridge_stop" + +# Mustang III v2 +ACTION=="add|change", SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ATTRS{idVendor}=="1ed8", ATTRS{idProduct}=="0016", GROUP="plugdev", RUN+="/bin/bash -c '/bin/echo /usr/local/bin/mustang_bridge_start | /usr/bin/at now'" +ACTION=="remove", ENV{ID_VENDOR_ID}=="1ed8", ENV{ID_MODEL_ID}=="0016", ENV{DEVTYPE}=="usb_device", RUN+="/usr/local/bin/mustang_bridge_stop" diff --git a/60-midi.rules b/60-midi.rules new file mode 100644 index 0000000..0ef0c83 --- /dev/null +++ b/60-midi.rules @@ -0,0 +1,2 @@ +ACTION=="add|change", SUBSYSTEM=="usb", ATTRS{idVendor}=="0763", ATTRS{idProduct}=="0160", RUN+="/bin/bash -c '/bin/echo /usr/local/bin/mustang_bridge_start | /usr/bin/at now'" +ACTION=="remove", ENV{ID_VENDOR_ID}=="0763", ENV{ID_MODEL_ID}=="0160", ENV{DEVTYPE}=="usb_device", RUN+="/usr/local/bin/mustang_bridge_stop" diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..40d4ddf --- /dev/null +++ b/install.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +BINDIR=/usr/local/bin +INITDIR=/etc/init.d +UDEVDIR=/etc/udev/rules.d + +if [ ! -f "mustang_midi" ]; then + echo "Must build mustang_midi first!" + exit 1 +fi + +echo "Create non-privileged user for MIDI bridge" + +useradd -M -s /bin/false mustang-user + +echo "Copy program and support scripts to $BINDIR" + +cp -f mustang_bridge_start $BINDIR +chmod 0755 $BINDIR/mustang_bridge_start +chown root:root $BINDIR/mustang_bridge_start + +cp -f mustang_bridge_stop $BINDIR +chmod 0755 $BINDIR/mustang_bridge_stop +chown root:root $BINDIR/mustang_bridge_stop + +cp -f mustang_midi $BINDIR +chmod 0755 $BINDIR/mustang_midi +chown root:root $BINDIR/mustang_midi + +echo "Copy init script to $INITDIR and register" + +cp -f mustang_bridge $INITDIR +chmod 0755 $INITDIR/mustang_bridge +chown root:root $INITDIR/mustang_bridge + +update-rc.d mustang_bridge defaults + +echo "Copy udev rules to $UDEVDIR and refresh system" + +cp -f 50-mustang.rules $UDEVDIR +chmod 0644 $UDEVDIR/50-mustang.rules +chown root:root $UDEVDIR/50-mustang.rules + +cp -f 60-midi.rules $UDEVDIR +chmod 0644 $UDEVDIR/60-midi.rules +chown root:root $UDEVDIR/60-midi.rules + +udevadm control --reload + +echo "Done!" diff --git a/mustang_bridge b/mustang_bridge new file mode 100755 index 0000000..016e2ab --- /dev/null +++ b/mustang_bridge @@ -0,0 +1,40 @@ +#! /bin/sh +### BEGIN INIT INFO +# Provides: mustang_bridge +# Required-Start: mountkernfs +# Required-Stop: +# Default-Start: S +# Default-Stop: +# Short-Description: Setup /var/run/mustang directory +### END INIT INFO + + +PATH=/sbin:/usr/sbin:/bin:/usr/bin + +. /lib/init/vars.sh +. /lib/lsb/init-functions + +do_start() { + [ -d /var/run/mustang ] || mkdir /var/run/mustang + if [ -z "$(ls -A -- "/var/run/mustang")" ]; then + touch /var/run/mustang/mustang_0000 + fi +} + +case "$1" in + start) + do_start + ;; + restart|reload|force-reload) + echo "Error: argument '$1' not supported" >&2 + exit 3 + ;; + stop|status) + # No-op + exit 0 + ;; + *) + echo "Usage: $0 start|stop" >&2 + exit 3 + ;; +esac diff --git a/mustang_bridge_start b/mustang_bridge_start new file mode 100755 index 0000000..17cb2c7 --- /dev/null +++ b/mustang_bridge_start @@ -0,0 +1,72 @@ +#!/usr/bin/python + +import os +from os.path import expanduser +from pwd import getpwnam +from grp import getgrnam + +import glob +import syslog +from string import split + +import usb.core + +####### Start User Edits ######### + +# Controller USB parms +control_vid = 0x0763 +control_pid = 0x0160 + +# Mustang USB parms +mustang_vid = 0x1ed8 +mustang_pid = 0x0016 + +# Controller MIDI device +midi_device = 2 + +# MIDI listen channel +midi_channel = 1 + +######## End User Edits ########## + +rundir = "/var/run/mustang/" + +# Look for devices +controller = usb.core.find( idVendor=control_vid, idProduct=control_pid ) +mustang = usb.core.find( idVendor=mustang_vid, idProduct=mustang_pid ) + +pid = os.getpid() +# syslog.syslog( "%d: Starting" % pid ) + +# was it found? +if controller and mustang: + os.chdir( rundir ) + filelist = glob.glob( 'mustang_*' ) + + if len( filelist ) == 1: + lockfile = filelist[0] + oldpid = split( lockfile, '_' )[1] + + # syslog.syslog( "%d: Check for path /proc/%s" % (pid, oldpid) ) + if not os.path.exists( "/proc/%s" % oldpid ): + # No such process, ok to start ours + # syslog.syslog( "%d: Renaming %s to mustang_%d" % (pid, lockfile, pid) ) + try: + os.rename( lockfile, "mustang_%d" % os.getpid() ) + except Exception, e: + pass + # syslog.syslog( "%d: Unable to rename file" % pid ) + else: + # syslog.syslog( "%d: About to exec" % pid ) + # Drop privileges and start the program + pwObj = getpwnam('mustang-user') + os.setgid( pwObj.pw_gid ) + + # Need secondary groups to access MIDI and USB devices + sec_gids = ( getgrnam('plugdev').gr_gid, getgrnam('audio').gr_gid ) + os.setgroups( sec_gids ) + + os.setuid( pwObj.pw_uid ) + os.execl( "/usr/local/bin/mustang_midi", "mustang_midi", "%s" % midi_device, "%s" % midi_channel ) + else: + syslog.syslog( "%d: /var/run/mustang is not properly setup" % pid ) diff --git a/mustang_bridge_stop b/mustang_bridge_stop new file mode 100755 index 0000000..bf77675 --- /dev/null +++ b/mustang_bridge_stop @@ -0,0 +1,35 @@ +#!/usr/bin/python + +import os +from glob import glob +from syslog import syslog +from string import split +import signal + +pid = os.getpid() +# syslog( "%d: Starting" % pid ) + +rundir = "/var/run/mustang/" + +# Check for pid file +os.chdir( rundir ) +filelist = glob( 'mustang_*' ) + +if len( filelist ) == 1: + lockfile = filelist[0] + oldpid = split( lockfile, '_' )[1] + + # See if the process still exists + # syslog( "%d: Check for path /proc/%s" % (pid, oldpid) ) + if os.path.exists( "/proc/%s" % oldpid ): + # syslog( "%d: Sending sigint to pid %s" % (pid, oldpid) ) + try: + os.kill( int(oldpid), signal.SIGINT ) + except Exception, e: + syslog( "%d: Signal failed: %s" % (pid, e) ) + pass + else: + # syslog( "%d: Signal sent" % pid ) + pass +else: + syslog( "%d: /var/run/mustang is not properly setup" % pid ) diff --git a/mustang_midi.cpp b/mustang_midi.cpp index f2b0f26..ee147fd 100644 --- a/mustang_midi.cpp +++ b/mustang_midi.cpp @@ -172,9 +172,8 @@ int main( int argc, const char **argv ) { // Don't want sysex, timing, active sense input_handler->ignoreTypes( true, true, true ); - std::cout << "\nTranslating MIDI input - press to quit.\n"; - char input; - std::cin.get(input); + // Block and wait for signal + pause(); delete input_handler; return 0;