XEN PVUSB: Unterschied zwischen den Versionen

Aus Neobikers Wiki
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
Zeile 61: Zeile 61:
# paravirtualized USB Support
# paravirtualized USB Support
#
#
# Version: $Revision: 1.4 $
# Version: $Revision: 1.5 $
# Datum:  $Date: 2009/08/23 17:06:54 $
# Datum:  $Date: 2009/08/23 20:28:30 $
#
#
# Author:  neobiker
# Author:  neobiker
#
#
# $Log: pvusb,v $
# $Log: pvusb,v $
# Revision 1.5  2009/08/23 20:28:30  root
# new options -t and -i
#
# Revision 1.4  2009/08/23 17:06:54  root
# Revision 1.4  2009/08/23 17:06:54  root
# optimization and code readability
# optimization and code readability
Zeile 92: Zeile 95:
{
{
   cat <<-EOT
   cat <<-EOT
         usage:  $(basename $0) -b
         usage:  $(basename $0) -b | -i | -l
                 $(basename $0) -d device_id -s domain [-c comment] -w
                 $(basename $0) -d <device_id> -s <domain> [-c comment] -w [ -t ]
                 $(basename $0) -u usb-port -s domain [-c comment] -w
                 $(basename $0) -u <usb-port> -s <domain> [-c comment] -w [ -t ]
                $(basename $0) -r
                $(basename $0) -x <usb-port>:<domain>:0:<vport>
     ------------
     ------------
     -b            # boot host with static defined PVUSB rules
     -b            # boot/initialise PVUSB with setup ($CONFIG)
    -i            # initialize PVUSB without any rules
     -s domain    # server domain_name or domain_id
     -s domain    # server domain_name or domain_id
     -u usb-port  # USB-PORT e.g. "3-2"
     -u usb-port  # USB-PORT e.g. "3-2"
Zeile 102: Zeile 108:
     -c comment    # e.g. "Canon IP4000"
     -c comment    # e.g. "Canon IP4000"
     -l            # list grabbed PVUSB Devices
     -l            # list grabbed PVUSB Devices
    -q            # be quiet
     -r            # read PVUSB rules
     -r            # list PVUSB rules
     -w            # write/activate PVUSB rule
     -w            # write/activate PVUSB rule
     -x            # delete PVUSB rule
     -x            # delete PVUSB rule
    -t            # try to trigger domain (per ssh)
    -q            # be quiet
EOT
EOT
}
}
Zeile 111: Zeile 118:
init ()
init ()
{
{
    PVUSB_INIT=0        # only a flag
     NUM_PORTS=8        # Max 16 PVUSB ports.
     NUM_PORTS=8        # Max 16 ports.


     CONFIG=/etc/xen/pvusb.conf
     CONFIG=/etc/xen/pvusb.conf
    PVUSB_PID=/var/run/pvusb_loadad.pid


     [ -e $CONFIG ] || cat >$CONFIG <<-EOT
     [ -e $CONFIG ] || cat >$CONFIG <<-EOT
Zeile 181: Zeile 186:
{
{
     # initialise backend only once
     # initialise backend only once
     [ "$PVUSB_INIT" ] || return
     [ "$PVUSB_INIT" = "1" ] && { PVUSB_INIT=1; return; }


     # 1) First, you have to start from the state that no device is connected.
     # 1) First, you have to start from the state that no device is connected.
Zeile 195: Zeile 200:


     # remember that pvusb is initialised
     # remember that pvusb is initialised
    echo $$ > $PVUSB_PID
    PVUSB_INIT=1
}
}


pvusb_setup_backend ()
pvusb_trigger_backend ()
{
{
     # connect USB devices to backend (and restart udevd afterwards)
     # connect USB devices to backend (and restart udevd afterwards)


     # call once the workaraound to remove Hostcontroller completly
     # XXX: find better way to connect USB devices dynamically!!!
    # XXX: oterhwise usbbk is already working?
    rmmod uhci_hcd ehci_hcd
    if [ $(cat $PVUSB_PID) -le $$ ]; then
    modprobe -a uhci_hcd ehci_hcd
 
        # XXX: better way to connect USB devices dynamically without udevd?
        rmmod uhci_hcd ehci_hcd
        modprobe -a uhci_hcd ehci_hcd
 
    else
        echo $$ > $PVUSB_PID
    fi


     # start udevd again after we have finished
     # start udevd again after we have finished
Zeile 243: Zeile 238:
     fi
     fi


    # get new vusb_port between 2 .. $NUM_PORTS
     vusb_port=$(get_vusb_port $usb_port)
     vusb_port=`cat /sys/bus/usb/drivers/usbback/vports | grep $usb_port | cut -d: -f4 | sort -n`
    if [ -z "$vusb_port" ]; then
        new_id=2
    else
        for ((i=2; $i<=$NUM_PORTS; i++)); do
            if [ -z "$(echo "$vusb_port" | grep $i)" ]; then
                new_id=$i
                break
            fi
        done
    fi
    vusb_port=$new_id


     # initialise paravirtualized USB Support in domain with vusb bus 0
     # initialise paravirtualized USB Support in domain with vusb bus 0
Zeile 272: Zeile 255:
         echo "xen PVUSB Rule written: $actual_vport $comment on domain $dom_name ($dom_id)"
         echo "xen PVUSB Rule written: $actual_vport $comment on domain $dom_name ($dom_id)"
     fi
     fi
}
get_vusb_port ()
{
    usb_port=$1
    # get new vusb_port between 2 .. $NUM_PORTS
    vports=`cat /sys/bus/usb/drivers/usbback/vports | grep $usb_port | cut -d: -f4 | sort -n`
    if [ -z "$vports" ]; then
        echo "2"
        return
    else
        for ((i=2; $i<=$NUM_PORTS; i++)); do
            if [ -z "$(echo $vports | grep $i)" ]; then
                echo "$i"
                return
            fi
        done
    fi
    echo "Error: no virtual USB-Port free for $usb_port" >2
}
}


Zeile 287: Zeile 290:
         adr=$(cat /sys/bus/usb/devices/$port/devnum)
         adr=$(cat /sys/bus/usb/devices/$port/devnum)
         if [ "$adr" = "$usb_adr" ]; then
         if [ "$adr" = "$usb_adr" ]; then
             usb_port=$port
             echo "$port"
             break
             return
         fi
         fi
     done
     done
     echo "$usb_port"
     echo "Error: no USB-Port not found for $usb_dev" >2
}
}


pvusb_write_connected_devices_static ()
pvusb_write_connected_devices_from_configfile ()
{
{
     # Define where to connect my USB-Devices (static definitions)
     # $CONFIG: where to connect my USB-Devices
     # -----------------------------------------------------------
     # ----------------------------------------
     #    see dmesg (syslog) where device ist connected:
     #    see dmesg (syslog) where device ist connected:
     #    e.g.: usb 3-2: new full speed USB device using uhci_hcd and address 4
     #    e.g.: usb 3-2: new full speed USB device using uhci_hcd and address 4
Zeile 308: Zeile 311:


         # where to connect my usb devices to?
         # where to connect my usb devices to?
         # list static definitions from $CONFIG
         # read static definitions from $CONFIG


         pvusb_conf=$(grep "$usb_dev" $CONFIG)
         pvusb_conf=$(grep "$usb_dev" $CONFIG)
Zeile 354: Zeile 357:
     # PVUSB initialising / prerequisits
     # PVUSB initialising / prerequisits
     # ------------------
     # ------------------
    [ -e $PVUSB_PID ] && rm $PVUSB_PID
     pvusb_init_backend
     pvusb_init_backend


     # PVUSB write backend rules
     # PVUSB write backend rules
     # -------------------------
     # -------------------------
     pvusb_write_connected_devices_static "$usb_devices"
     pvusb_write_connected_devices_from_configfile "$usb_devices"
}
}


Zeile 365: Zeile 367:
{
{
     # PVUSB trigger for all relevant domains
     # PVUSB trigger for all relevant domains
    # --------------------------------------
    [ -n "$1" ] || return
    # tell PV domain to reload USB
     # XXX: better way to trigger domU?
     # XXX: better way to trigger domU?
     for domain in $(echo "$1" | sort -u); do
     for domain in $(echo "$1" | sort -u); do
         ssh $domain "[ -n \"\$(lsusb | grep -v '0000:0000')\" ] || exit 0 ;
         ssh $domain "[ -n \"\$(lsusb || true)\" ] && exit 0 ;
                     rmmod xen_hcd usbcore ;
                     rmmod xen_hcd usbcore ;
                     modprobe xen_hcd
                     modprobe xen_hcd
Zeile 400: Zeile 398:
init
init


while getopts ":bc:d:hlqrs:u:wx:" opt; do
while getopts ":bc:d:Dhilqrs:tu:wx:" opt; do
   case $opt in
   case $opt in
     b) # boot host with static defined rules
     b) # boot host with setup rules in $CONFIG
       pvusb_boot_init
       pvusb_boot_init
       pvusb_setup_backend
       pvusb_trigger_backend
       pvusb_trigger $PVUSB_DOMAINS
       pvusb_trigger $PVUSB_DOMAINS
      ;;
    i) # initialise PVUSB without any rules
      pvusb_init_backend
      pvusb_trigger_backend
       ;;
       ;;
     c) # comment  e.g. Canon IP4000
     c) # comment  e.g. Canon IP4000
Zeile 425: Zeile 427:
       ;;
       ;;
     s) # Server Domain-name or -id
     s) # Server Domain-name or -id
       domain=$OPTARG
       domain=$(xm domname $OPTARG)    # check if domain exists
       if [ "$domain" = "$(echo $domain | tr -d [:alpha:])" ]; then
       ;;
          domain=$(xm domname $domain)
    t) # try to trigger domain with ssh
      fi
      pvusb_trigger $PVUSB_DOMAINS $domain
       ;;
       ;;
     u) # USB-PORT (3-2)
     u) # USB-PORT (3-2)
Zeile 436: Zeile 438:
       pvusb_init_backend
       pvusb_init_backend
       pvusb_write_rule $domain $usb_port "$comment"
       pvusb_write_rule $domain $usb_port "$comment"
       pvusb_setup_backend
       pvusb_trigger_backend
       #pvusb_trigger $PVUSB_DOMAINS
       pvusb_trigger $PVUSB_DOMAINS
       LIST_PVUSB=1
       LIST_PVUSB=1
       ;;
       ;;
     x) # delete PVUSB rule
     x) # delete PVUSB rule
       echo "$OPTARG" > /sys/bus/usb/drivers/usbback/remove_vport || true
       echo "$OPTARG" > /sys/bus/usb/drivers/usbback/remove_vport || true
      ;;
    D) set -x
       ;;
       ;;
     \?)
     \?)

Version vom 23. August 2009, 21:35 Uhr

PVUSB mit XEN 3.4

Bei mir gab es Probleme mit USB per PCI-Delegation unter XEN 3.4.1 auf Lenny (die Netzwerkkarten gingen, lsusb hat auch die USB Hostcontroller angezeigt, aber es wurden keine USB-Devices sichtbar), deshalb habe ich die seit Xen 3.4 neue USB-Virtualisierung PVUSB (paravirtualized USB support for Xen, Details siehe hier) getestet und unter Lenny eingebaut. Dabei ist folgendes Skript herausgekommen, welches ich in '/etc/rc.local' als pvusb -b aufrufe, um beim booten des Host-Systems den USB-Drucker an meine Printer-Domain durchzureichen.

Beispiele PVUSB Konfigfile zum automatischen Verbinden von USB-Devices z.B. beim booten des XEN Hostsystems. Ich verbinde meinen USB-Drucker nach dem Start mit meinen CUPS Printserver (srv), und USB-Sticks z.B. mit dem Webserver in der DMZ (dmz).

File /etc/xen/pvusb.conf

# Configfile for pvusb
# Device_Id Domain Comment
04a9:1093 srv Canon IP4000
13fe:1d00 srv Sun USB-Stick 1GB
090c:1000 dmz Novell USB-Stick 2GB

File /etc/rc.local

#!/bin/sh
...
/usr/local/sbin/pvusb -b
...

Beispiele für pvusb

m450:~# pvusb -h
usage:  pvusb -b
        pvusb -d device_id -s domain [-c comment] -w
        pvusb -u usb-port  -s domain [-c comment] -w
    ------------
    -b            # boot host with static defined PVUSB rules
    -s domain     # server domainname or -id
    -u usb-port   # USB-PORT e.g. "3-2"
    -d device_id  # USB device_id e.g. "0912:1234"
    -c comment    # e.g. "Canon IP4000"
    -l            # list (default) actual PVUSB Devices
    -q            # don't list PVUSB Devices
    -r            # list PVUSB rules
    -w            # write/activate PVUSB rule
    -x            # delete PVUSB rule

m450:~# pvusb -l
PVUSB: 3-2 on srv (3) 04a9:1093 Canon, Inc. PIXMA iP4000

m450:~# pvusb -r
5-1:5:0:2
3-2:3:0:3
5-2:3:0:2

m450:~# pvusb -x 5-2:3:0:2

m450:~# pvusb -r
5-1:5:0:2
3-2:3:0:3

File /usr/local/sbin/pvusb

#!/bin/sh
#
# paravirtualized USB Support
#
# Version: $Revision: 1.5 $
# Datum:   $Date: 2009/08/23 20:28:30 $
#
# Author:  neobiker
#
# $Log: pvusb,v $
# Revision 1.5  2009/08/23 20:28:30  root
# new options -t and -i
#
# Revision 1.4  2009/08/23 17:06:54  root
# optimization and code readability
#
# Revision 1.3  2009/08/22 19:35:40  root
# bugfix convert dom_id+dom_nam
#
# Revision 1.2  2009/08/21 22:24:27  root
# bugfix: rename $server to $domain
#
# Revision 1.1  2009/08/20 20:28:14  root
# Initial revision
#

LSUSB=$(lsusb||echo "Error")
if [ "$LSUSB" = "Error" ]; then
    echo "Error: Missing /usr/bin/lsusb, please install usbutils"
    exit 1
fi

set -e
#set -x

usage ()
{
  cat <<-EOT
        usage:  $(basename $0) -b | -i | -l
                $(basename $0) -d <device_id> -s <domain> [-c comment] -w [ -t ]
                $(basename $0) -u <usb-port> -s <domain> [-c comment] -w [ -t ]
                $(basename $0) -r
                $(basename $0) -x <usb-port>:<domain>:0:<vport>
    ------------
    -b            # boot/initialise PVUSB with setup ($CONFIG)
    -i            # initialize PVUSB without any rules
    -s domain     # server domain_name or domain_id
    -u usb-port   # USB-PORT e.g. "3-2"
    -d device_id  # USB device_id e.g. "0912:1234"
    -c comment    # e.g. "Canon IP4000"
    -l            # list grabbed PVUSB Devices
    -r            # read PVUSB rules
    -w            # write/activate PVUSB rule
    -x            # delete PVUSB rule
    -t            # try to trigger domain (per ssh)
    -q            # be quiet
EOT
}

init ()
{
    NUM_PORTS=8         # Max 16 PVUSB ports.

    CONFIG=/etc/xen/pvusb.conf

    [ -e $CONFIG ] || cat >$CONFIG <<-EOT
        # Configfile for pvusb
        # 'pvusb -b' connects Device_Id to Domain
        # Device_Id  Domain Comment
        # 1234:5678 server USB-Printer
EOT
}

#
# paravirtualized USB Support
# ---------------------------

pvusb_init_xenstore ()
{
    # Setup and initialize the XenStore for PVUSB
    # based on init_xs.sh by Noboru Iwamatsu

    dom_id=$1
    vusb_bus=$2         # vusb_bus (typical 0)

    XSWRITE=/usr/bin/xenstore-write
    XSCHMOD=/usr/bin/xenstore-chmod

    # Write backend information into the location that frontend look for.
    $XSWRITE /local/domain/$dom_id/device/vusb/$vusb_bus/backend-id 0
    $XSWRITE /local/domain/$dom_id/device/vusb/$vusb_bus/backend \
             /local/domain/0/backend/vusb/$dom_id/$vusb_bus

    # Write frontend information into the location that backend look for.
    $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend-id $dom_id
    $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend \
             /local/domain/$dom_id/device/vusb/$vusb_bus

    # Write virtual root hub field.
    $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/num-ports $NUM_PORTS
    for i in $(seq 1 $NUM_PORTS)
    do
        # Set all port to disconnected state
        $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port-$i "0"
    done

    # Set permission
    $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus n$dom_id r0
    $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/backend-id n$dom_id r0
    $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/backend n$dom_id r0
    $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus n0 r$dom_id
    $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend-id n0 r$dom_id
    $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend n0 r$dom_id
    $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/num-ports n0 r$dom_id
    for i in $(seq 1 $NUM_PORTS)
    do
        $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port-$i n0 r$dom_id
    done

    # Set state to XenbusStateInitialising
    $XSWRITE /local/domain/$dom_id/device/vusb/$vusb_bus/state 1
    $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/state n$dom_id r0
    $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/state 1
    $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/state n0 r$dom_id
}

pvusb_init_backend ()
{
    # initialise backend only once
    [ "$PVUSB_INIT" = "1" ] && { PVUSB_INIT=1; return; }

    # 1) First, you have to start from the state that no device is connected.
    #    remove all usb modules but usbbk
    usb_mods="$(lsmod | grep usb | grep -v usbcore | grep -v usbbk | awk '/^usb/ {print $1}')"
    [ -n "$usb_mods" ] && rmmod $usb_mods

    # stop udevd fetching events before the backend driver
    udevadm control --stop_exec_queue

    # load usb (backend) modules
    modprobe usbbk

    # remember that pvusb is initialised
}

pvusb_trigger_backend ()
{
    # connect USB devices to backend (and restart udevd afterwards)

    # XXX: find better way to connect USB devices dynamically!!!
    rmmod uhci_hcd ehci_hcd
    modprobe -a uhci_hcd ehci_hcd

    # start udevd again after we have finished
    udevadm control --start_exec_queue
}

pvusb_write_rule ()
{
    domain=$1           # domain to connect PVUSB Port
    usb_port=$2         # where is usb device connected
    comment=$3          # a name for usb device
    vusb_bus=0          # virtual USB Bus in domain (we use always usb bus 0)

    if [ -z "$domain" ]; then
        echo "missing option -s <domain>"
        return
    fi
    if [ -z "$usb_port" ]; then
        echo "missing option -u <usb_port>"
        return
    fi

    if [ "$domain" = "$(echo $domain | tr -d [:alpha:])" ]; then
        dom_name=$(xm domname $domain)
        dom_id=$domain
    else
        dom_name=$domain
        dom_id=$(xm domid $domain)
    fi

    vusb_port=$(get_vusb_port $usb_port)

    # initialise paravirtualized USB Support in domain with vusb bus 0
    pvusb_init_xenstore $dom_id $vusb_bus

    # 2) test and remove existing hotplug-rule
    actual_vport=$(cat /sys/bus/usb/drivers/usbback/vports | awk "/$usb_port/"'{print}')
    [ -n "$actual_vport" ] && echo "$actual_vport" > /sys/bus/usb/drivers/usbback/remove_vport

    # 2) Write the hotplug-rule through the sysfs interface of the backenend driver
    echo "$usb_port:$dom_id:$vusb_bus:$vusb_port" > /sys/bus/usb/drivers/usbback/new_vport

    # tell me what happened
    if [ -z "$QUIET" ]; then
        actual_vport=$(cat /sys/bus/usb/drivers/usbback/vports | awk "/$usb_port/"'{print}')
        echo "xen PVUSB Rule written: $actual_vport $comment on domain $dom_name ($dom_id)"
    fi
}

get_vusb_port ()
{
    usb_port=$1

    # get new vusb_port between 2 .. $NUM_PORTS
    vports=`cat /sys/bus/usb/drivers/usbback/vports | grep $usb_port | cut -d: -f4 | sort -n`
    if [ -z "$vports" ]; then
        echo "2"
        return
    else
        for ((i=2; $i<=$NUM_PORTS; i++)); do
            if [ -z "$(echo $vports | grep $i)" ]; then
                echo "$i"
                return
            fi
        done
    fi
    echo "Error: no virtual USB-Port free for $usb_port" >2
}

get_usb_port ()
{
    usb_dev="$1"
    usb_port=""

    # find out where USB-Device is connected
    usb_ports="$(/bin/ls -1 /sys/bus/usb/devices/ | awk '/^[0-9]\-[0-9]$/ {print}')"
    usb_bus=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$2}')
    usb_adr=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$4}')

    for port in $(echo "$usb_ports"|grep "$usb_bus"); do
        adr=$(cat /sys/bus/usb/devices/$port/devnum)
        if [ "$adr" = "$usb_adr" ]; then
            echo "$port"
            return
        fi
    done
    echo "Error: no USB-Port not found for $usb_dev" >2
}

pvusb_write_connected_devices_from_configfile ()
{
    # $CONFIG: where to connect my USB-Devices
    # ----------------------------------------
    #    see dmesg (syslog) where device ist connected:
    #    e.g.: usb 3-2: new full speed USB device using uhci_hcd and address 4

    devices="$1"
    # XXX: only normal USB-Ports (1-1) are supported yet, no cascaded USB-Hubs (1-1.1)
    usb_ports="$(/bin/ls -1 /sys/bus/usb/devices/ | awk '/^[0-9]\-[0-9]$/ {print}')"

    for usb_dev in $devices; do

        # where to connect my usb devices to?
        # read static definitions from $CONFIG

        pvusb_conf=$(grep "$usb_dev" $CONFIG)
        if [ -n "$pvusb_conf" ]; then
            domain=$(echo $pvusb_conf | awk '{print $2}')
            comment=$(echo $pvusb_conf | cut -d\  -f3-)
        else
            continue
        fi

        # find out where USB-Device is connected
        usb_bus=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$2}')
        usb_adr=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$4}')
        for port in $(echo "$usb_ports" | grep "$usb_bus"); do
            adr=$(cat /sys/bus/usb/devices/$port/devnum)
            if [ "$adr" = "$usb_adr" ]; then
                usb_port=$port
                break
            fi
        done
        echo "found $comment ($usb_dev) on USB-Port $usb_port"

        # PVUSB write xen backend rules for usb device
        # --------------------------------------------
        pvusb_write_rule $domain $usb_port "$comment"

        # remember domain to be triggered
        PVUSB_DOMAINS=$(cat <<-EOT | sort -u
                $PVUSB_DOMAINS
                $domain)
    done
}

pvusb_boot_init ()
{
    # get all connected USB devices
    usb_devices=$(echo "$LSUSB" | grep -v '0000:0000' | awk '{print $6}')

    # ready if no devices are found
    if [ -z "$usb_devices" ]; then
        echo "$(basename $0): No USB Devices found"
        return
    fi

    # PVUSB initialising / prerequisits
    # ------------------
    pvusb_init_backend

    # PVUSB write backend rules
    # -------------------------
    pvusb_write_connected_devices_from_configfile "$usb_devices"
}

pvusb_trigger ()
{
    # PVUSB trigger for all relevant domains
    # XXX: better way to trigger domU?
    for domain in $(echo "$1" | sort -u); do
        ssh $domain "[ -n \"\$(lsusb || true)\" ] && exit 0 ;
                     rmmod xen_hcd usbcore ;
                     modprobe xen_hcd
                    " || true
    done
}

pvusb_list ()
{
    # tell me what happened
    # ---------------------
    pvusb_grabbed=$(cat /sys/bus/usb/drivers/usbback/grabbed_devices)

    for pvusb in $pvusb_grabbed; do
        usb_port=$(echo $pvusb | awk -F: '{print $1}')
        dom_id=$(cat /sys/bus/usb/drivers/usbback/vports | awk -F: "/$usb_port/"' {print $2}')
        dev_id="$(cat /sys/bus/usb/devices/$usb_port/idVendor)"
        dev_id="$dev_id:$(cat /sys/bus/usb/devices/$usb_port/idProduct)"
        product=$(echo "$LSUSB" | grep $dev_id | cut -d\  -f6-)

        echo "PVUSB: $usb_port on `xm domname $dom_id` ($dom_id) $product"
    done
}

# ------------------------
# Script starts here
# ------------------------
init

while getopts ":bc:d:Dhilqrs:tu:wx:" opt; do
  case $opt in
    b) # boot host with setup rules in $CONFIG
      pvusb_boot_init
      pvusb_trigger_backend
      pvusb_trigger $PVUSB_DOMAINS
      ;;
    i) # initialise PVUSB without any rules
      pvusb_init_backend
      pvusb_trigger_backend
      ;;
    c) # comment  e.g. Canon IP4000
      comment=$OPTARG
      ;;
    d) # USB DEVICE_ID (0912:1234)
      usb_port=$(get_usb_port $OPTARG)
      ;;
    h) usage
      ;;
    l) # list PVUSB Ports
      LIST_PVUSB=1
      ;;
    q) # don't list PVUSB Ports
      QUIET=0
      ;;
    r) # list rules
      cat /sys/bus/usb/drivers/usbback/vports
      ;;
    s) # Server Domain-name or -id
      domain=$(xm domname $OPTARG)    # check if domain exists
      ;;
    t) # try to trigger domain with ssh
      pvusb_trigger $PVUSB_DOMAINS $domain
      ;;
    u) # USB-PORT (3-2)
      usb_port=$OPTARG
      ;;
    w) # write rule PVUSB
      pvusb_init_backend
      pvusb_write_rule $domain $usb_port "$comment"
      pvusb_trigger_backend
      pvusb_trigger $PVUSB_DOMAINS
      LIST_PVUSB=1
      ;;
    x) # delete PVUSB rule
      echo "$OPTARG" > /sys/bus/usb/drivers/usbback/remove_vport || true
      ;;
    D) set -x
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      ;;
  esac
done

[ "$LIST_PVUSB" = "1" ] && pvusb_list