XEN PVUSB: Unterschied zwischen den Versionen

Aus Neobikers Wiki
Zur Navigation springen Zur Suche springen
Keine Bearbeitungszusammenfassung
Keine Bearbeitungszusammenfassung
 
(40 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
=== PVUSB mit XEN 3.4 ===
=== 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 [http://www.nabble.com/-RFC--PATCH-0-4--PVUSB:-add-paravirtualized-USB-support-for-Xen-td22550607.html 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.
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 [http://lists.xensource.com/archives/html/xen-devel/2009-03/msg01084.html 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.


File ''/usr/sbin/'''''pvusb'''
'''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).
 
Die USB DeviceIDs (z.B. '04a9:1093') kann man mit dem Komamndo ''lsusb'' ermitteln. Die USB-Ports  (z.B. '3-2') werden beim Anstecken der Devices auf der Systemkonsole (Dom0) angezeigt.
 
File '''/etc/xen/pvusb.conf'''
<pre>
# Configfile for pvusb
# Dev_Id    <domain> <Comment>
# USBPort  <domain> <Comment>
# 0000:0000 <domain> <Comment>
04a9:1093  srv      Canon Printer IP4000
5-1        dmz      Anything on USB Port 5-1
0000:0000  vm01    initialize 'vm01' for PVUSB
</pre>
 
File '''/etc/rc.local'''
 
Für die Option ''-t'' ("Trigger Domain") muss SSH Access per SSH-Keys funktionieren, da mit ''ssh <domain> <Befehle>'' versucht wird, Remote-Kommandos innerhalb der Domain auszuführen.
<pre>#!/bin/sh
<pre>#!/bin/sh
...
/usr/local/sbin/pvusb -b
...
</pre>
Beispiele für ''pvusb''
<pre>
m450:~# pvusb -h
usage:  pvusb -b [-t] | -i
        pvusb -s <domain> -a [ -t ]
        pvusb -d <device_id> -s <domain> [-c <comment>] -w [ -t ]
        pvusb -u <usb-port> -s <domain> [-c <comment>] -w [ -t ]
        pvusb -l | -r
        pvusb -x <usb-port>:<domain>:0:<vport>
    ------------
    -a            # activate PVUSB (for -s <domain>)
    -b            # boot/initialise PVUSB with hotplug rules (/etc/xen/pvusb.conf)
    -i            # initialize PVUSB without hotplug rules (/etc/xen/pvusb.conf)
    -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' (use 'lsusb' to get the ID)
    -c <comment>  # e.g. "Canon IP4000 Printer"
    -l            # list grabbed PVUSB Devices
    -r            # read PVUSB hotplug rules
    -w            # write/activate PVUSB hotplug rule
    -x            # delete PVUSB hotplug rule (use copy/paste from -r list)
    -t            # try to trigger all domains (per ssh) to init PVUSB
    -q            # be quiet
    -D            # Debug option (set -x)
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
</pre>
Dieses Skript funktioniert nicht mit Xen 3.4.3, wegen Änderungen im xenstore. Ab XEN 4.0 kann im Konfigfile die Option ''vusb = [ 'usbver=2, numports=8, port_1=5-8' ]'' verwendet werden.
Skript für '''XEN 3.4.3''' siehe weiter unten!
Das Skript ''/usr/local/sbin/'''''pvusb''' für '''Xen 3.4.2'''
<pre>
#!/bin/sh
#
#
# paravirtualized USB Support
# paravirtualized USB Support (XEN 3.4.2)
#
#
# Version: $Revision$
# Version: $Revision: 1.15 $
# Datum:  $Date$
# Datum:  $Date: 2009/08/31 07:28:49 $
#
#
# Author:  neobiker
# Author:  neobiker
#
#
# $Log$
# $Log: pvusb,v $
# Revision 1.15  2009/08/31 07:28:49  root
# init_xenstore (): call init_backend () if needed
#
# Revision 1.14  2009/08/26 17:15:17  root
# updated usage () and some info's
#
# Revision 1.13  2009/08/26 07:12:35  root
# bugfix: get_free_vusb_port ()
# check if xenstore is initialized
#
# Revision 1.12  2009/08/25 20:05:43  root
# some optimization and error handling
#
# Revision 1.11  2009/08/24 19:01:36  root
# rename _trigger_backend () to _connect_backend ()
#
# Revision 1.10  2009/08/24 18:52:53  root
# bugfix: lsusb test fixed, ohci_hcd added
#
# Revision 1.9  2009/08/23 23:50:35  root
# bugfix with domain not started
#
# Revision 1.8  2009/08/23 23:14:05  root
# use -t to trigger domain needed
#
# Revision 1.7  2009/08/23 21:41:27  root
# optimzed trigger_backend
#
# Revision 1.6  2009/08/23 21:01:21  root
# read USB-Ports from $CONFIG
#
# 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 2>/dev/null | grep -v '0000:0000' || echo "Error")
if [ "$LSUSB" = "Error" ]; then
    echo "Error: Missing command 'lsusb', please install usbutils"
    exit 1
fi


set -e
set -e
#set -x


usage ()
usage ()
{
{
   cat <<-EOT
   cat <<-EOT
         usage:  $(basename $0) -b
         usage:  $(basename $0) -b [-t] | -i
                 $(basename $0) -d device_id -s domain [-c comment] -w
                $(basename $0) -s <domain> -a [ -t ]
                 $(basename $0) -u usb-port -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 [ -t ]
                $(basename $0) -l | -r
                $(basename $0) -x <usb-port>:<domain>:0:<vport>
     ------------
     ------------
     -b            # boot host with static defined PVUSB rules
    -a            # activate PVUSB (for -s <domain>)
     -s domain     # server domainname or -id
     -b            # boot/initialise PVUSB with hotplug rules ($CONFIG_FILE)
     -u usb-port   # USB-PORT e.g. "3-2"
    -i            # initialize PVUSB without hotplug rules ($CONFIG_FILE)
     -d device_id # USB device_id e.g. "0912:1234"
     -s <domain# server domain_name or domain_id
     -c comment   # e.g. "Canon IP4000"
     -u <usb-port> # USB-PORT e.g. '3-2'
     -l            # list (default) actual PVUSB Devices
     -d <device_id># USB device_id e.g. '0912:1234' (use 'lsusb' to get the ID)
     -q           # don't list PVUSB devices
     -c <comment# e.g. "Canon IP4000 Printer"
     -w            # write/activate PVUSB rule
     -l            # list grabbed PVUSB Devices
     -r           # read PVUSB hotplug rules
     -w            # write/activate PVUSB hotplug rule
    -x            # delete PVUSB hotplug rule (use copy/paste from -r list)
    -t            # try to trigger all domains (per ssh) to init PVUSB
    -q            # be quiet
    -D            # Debug option (set -x)
EOT
EOT
}
}
Zeile 38: Zeile 168:
init ()
init ()
{
{
     VUSB_ID=0
     NUM_PORTS=8        # Max 16 PVUSB ports.
     LIST_PVUSB=1
     VUSB_BUS=0          # virtual USB Bus in <domain> (we use always usb bus 0)
     CONFIG=/etc/xen/pvusb.conf
 
     CONFIG_FILE=/etc/xen/pvusb.conf
 
    [ -e $CONFIG_FILE ] || cat >$CONFIG_FILE <<-EOT
        # Configfile for pvusb
        # 'pvusb -b' connects <Device_Id> / <USB-Port> to <Domain>
        # 'pvusb -i' initializes <Domain> for PVUSB
 
        # <Device_Id>  <Domain> <Comment>
        # 1234:5678    server  USB-Printer on an USB-Port
 
        # <USB-Port>  <Domain> <Comment>
        # 3-2          server  Any Device on Port 3-2


    [ -e $CONFIG ] || cat >$CONFIG <<EOT
        # <Device_Id> <Domain> <Comment>
# Configfile for pvusb
        # 0000:0000    server  initialize 'server' for PVUSB
# Device_Id  Domain Comment
EOT
EOT
    CONFIG=$(cat $CONFIG_FILE | sed -e 's/#.*$//' -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e '/^$/ d' -e '/^[[:graph:]]*$/ d')
}
}


Zeile 57: Zeile 200:
     # based on init_xs.sh by Noboru Iwamatsu
     # based on init_xs.sh by Noboru Iwamatsu


     FRONT_ID=$(xm domid "$1")  # use domain id if dommane given
     dom_id=$1
     DEV_ID=$2                   # vusb_bus typical 0
     vusb_bus=$2         # vusb_bus (typical 0)


     DEV_NAME=vusb       # fix name
     # check if xenstore is already initialized
     NUM_PORTS=8        # Max 16 ports.
    [ -e /sys/devices/xen-backend/vusb-$dom_id-$vusb_bus ] && return
 
    # check if PVUSB is already initialized
     [ -e /sys/bus/xen-backend/drivers/vusb ] || pvusb_init_backend


     XSWRITE=/usr/bin/xenstore-write
     XSWRITE=/usr/bin/xenstore-write
Zeile 67: Zeile 213:


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


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


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


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


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


pvusb_init ()
pvusb_init_backend ()
{
{
     [ "$VUSB_ID" ] || return
    # initialise backend only once
    VUSB_ID=1
     [ "$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 113: Zeile 259:
     usb_mods="$(lsmod | grep usb | grep -v usbcore | grep -v usbbk | awk '/^usb/ {print $1}')"
     usb_mods="$(lsmod | grep usb | grep -v usbcore | grep -v usbbk | awk '/^usb/ {print $1}')"
     [ -n "$usb_mods" ] && rmmod $usb_mods
     [ -n "$usb_mods" ] && rmmod $usb_mods
    # stop udevd fetching events before the backend driver
    udevadm control --stop_exec_queue


     # load usb (backend) modules
     # load usb (backend) modules
Zeile 121: Zeile 264:
}
}


pvusb_setup ()
pvusb_connect_backend ()
{
{
     # connect USB devices to backend (and restart udevd afterwards)
     # connect USB devices to backend (and restart udevd afterwards)
     # XXX: better way to connect USB devices dynamically without udevd?
 
     rmmod uhci_hcd ehci_hcd
    # stop udevd fetching events before the backend driver
     modprobe -a uhci_hcd ehci_hcd
    udevadm control --stop_exec_queue
 
     # XXX: find better way to connect USB devices dynamically!!!
     rmmod uhci_hcd ehci_hcd ohci_hcd 2>/dev/null || true
     modprobe -a uhci_hcd ehci_hcd ohci_hcd || true


     # start udevd again after we have finished
     # start udevd again after we have finished
Zeile 132: Zeile 279:
}
}


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


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


     # initialise paravirtualized USB Support in domain with pv-usb bus 0
    if [ "$domain" = "$(echo $domain | tr -d [:alpha:])" ]; then
     pvusb_init_xenstore $dom_id $vusb_bus
        dom_name=$(xm domname $domain)
        dom_id=$domain
    else
        dom_name=$domain
        dom_id=$(xm domid $domain)
    fi
 
    # get the next free USB Port in <domain>
    vusb_port=$(get_free_vusb_port $dom_id)
 
     # 1) initialise paravirtualized USB Support for dom_id
     pvusb_init_xenstore $dom_id $VUSB_BUS


     # 2) test and remove existing hotplug-rule
     # 2a) test and remove existing hotplug-rule
     actual_vport=$(cat /sys/bus/usb/drivers/usbback/vports | awk "/$usb_bus/"'{print}')
     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
     [ -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
     # 2b) Write the hotplug-rule through the sysfs interface of the backenend driver
     echo "$usb_bus:$dom_id:$vusb_bus:$VUSB_ID" > /sys/bus/usb/drivers/usbback/new_vport
     echo "$usb_port:$dom_id:$VUSB_BUS:$vusb_port" > /sys/bus/usb/drivers/usbback/new_vport


     # tell me what happened
     # tell me what happened
     actual_vport=$(cat /sys/bus/usb/drivers/usbback/vports | awk "/$usb_bus/"'{print}')
     if [ -z "$QUIET" ]; then
    echo "xen PVUSB Rule written: $actual_vport $comment on domain $DOM_NAME ($dom_id)"
        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_free_vusb_port ()
{
    # get new vusb_port between 2 .. $NUM_PORTS
    dom_id=$1
    vports=$(cat /sys/bus/usb/drivers/usbback/vports | awk -v FS=: "/^.*:$dom_id:.*:.*/ {print \$4}")
    if [ -z "$vports" ]; then
        echo "2"
        return
    else
        for ((i=2; $i<=$NUM_PORTS; i++)); do
          for vport in $vports; do
              [ "$vport" -eq $i ] && break
          done
          [ $vport -ne $i ] && { echo "$i"; return; }
        done
    fi
    echo "Error: no virtual USB-Port free for $dom_id" >&2
    exit 1
}
}


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


     for port in $(echo "$usb_ports"|grep "$usb_bus"); do
     for port in $(echo "$usb_ports" | grep $usb_bus || true); do
         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 found for $usb_dev" >&2
}
 
pvusb_init_domains_from_configfile ()
{
    domains=$(echo "$CONFIG" | awk '/^0000:0000 / {print $2}')
 
    for domain in $domains; do
        dom_id=$(xm domid $domain || continue)
 
        [ -n "$dom_id" ] || continue
        pvusb_init_xenstore $dom_id $VUSB_BUS
 
        # remember domain to be triggered
        PVUSB_DOMAINS=$(cat <<-EOT | sort -u
                $PVUSB_DOMAINS
                $domain)
    done
}
}


pvusb_write_connected_devices_static ()
pvusb_write_defined_ports_from_configfile ()
{
{
     # Define where to connect my USB-Devices (static definitions)
     # $CONFIG: where to connect the USB-Ports
    # -----------------------------------------------------------
    # ---------------------------------------
    ports=$(echo "$CONFIG" | awk '/^[0-9]-[0-9] / {print $1}')
 
    for usb_port in $ports; do
 
        # read static definitions from $CONFIG
        pvusb_conf=$(echo "$CONFIG" | grep $usb_port | tail -1)
        if [ -n "$pvusb_conf" ]; then
            domain=$(echo $pvusb_conf | awk '{print $2}')
            comment=$(echo $pvusb_conf | cut -d\  -f3-)
            [ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue
 
        else
            continue
        fi
 
        # 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_write_connected_devices_from_configfile ()
{
    # $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


     devices="$1"
     # 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 connected USB Devices found."
        return
    fi
 
    # 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}')"
     usb_ports="$(/bin/ls -1 /sys/bus/usb/devices/ | awk '/^[0-9]\-[0-9]$/ {print}')"


     for usb_dev in $devices; do
     for usb_dev in $usb_devices; do


         # 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=$(echo "$CONFIG" | grep $usb_dev | tail -1)
         if [ -n "$pvusb_conf" ]; then
         if [ -n "$pvusb_conf" ]; then
             server=$(echo $pvusb_conf | awk '{print $2}')
             domain=$(echo $pvusb_conf | awk '{print $2}')
             comment=$(echo $pvusb_conf | cut -d\  -f3-)
             comment=$(echo $pvusb_conf | cut -d\  -f3-)
            # skip if <domain> isn't activ
            [ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue
         else
         else
             continue
             continue
Zeile 208: Zeile 443:


         # find out where USB-Device is connected
         # find out where USB-Device is connected
         usb_bus=$(lsusb | grep $usb_dev | awk '{printf "%d",$2}')
         usb_bus=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$2}')
         usb_adr=$(lsusb | grep $usb_dev | awk '{printf "%d",$4}')
         usb_adr=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$4}')
         for port in $(echo "$usb_ports"|grep "$usb_bus"); do
         for port in $(echo "$usb_ports" | grep $usb_bus || true); do
             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
Zeile 217: Zeile 452:
             fi
             fi
         done
         done
        if [ -z "$usb_port" ]; then
            echo "Error: No USB Port found for $usb_dev"
            continue
        fi
         echo "found $comment ($usb_dev) on USB-Port $usb_port"
         echo "found $comment ($usb_dev) on USB-Port $usb_port"


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


         # remember domain to be triggered
         # remember domain to be triggered
Zeile 230: Zeile 469:
}
}


pvusb_boot_host ()
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 || true ;
                    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 2>/dev/null || echo "<inactiv>") ($dom_id) $product"
    done
}
# ------------------------
# Script starts here
# ------------------------
init
while getopts ":abc:d:Dhilqrs:tu:wx:" opt; do
  case $opt in
    a) # activate PVUSB for <domain> without any rules
      dom_id=$(xm domid $domain)
      pvusb_init_xenstore $dom_id $VUSB_BUS
      ;;
    b) # boot host with setup rules in $CONFIG
      pvusb_init_backend
      pvusb_init_domains_from_configfile
      pvusb_write_connected_devices_from_configfile
      pvusb_write_defined_ports_from_configfile
      pvusb_connect_backend
      ;;
    i) # initialise PVUSB without any rules
      pvusb_init_backend
      pvusb_init_domains_from_configfile
      pvusb_connect_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_write_rule $domain $usb_port "$comment"
      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
</pre>
Das Skript für '''XEN 3.4.3'''
<pre>#!/bin/sh
#
# paravirtualized USB Support (XEN 3.4.3)
#
# Version: $Revision: 1.16 $
# Datum:  $Date: 2010/06/26 15:42:21 $
#
# Author:  neobiker
#
# $Log: pvusb,v $
# Revision 1.16  2010/06/26 15:42:21  root
# Changes for XEN 3.4.3
#
# Revision 1.15  2009/08/31 07:28:49  root
# init_xenstore (): call init_backend () if needed
#
# Revision 1.14  2009/08/26 17:15:17  root
# updated usage () and some info's
#
# Revision 1.13  2009/08/26 07:12:35  root
# bugfix: get_free_vusb_port ()
# check if xenstore is initialized
#
# Revision 1.12  2009/08/25 20:05:43  root
# some optimization and error handling
#
# Revision 1.11  2009/08/24 19:01:36  root
# rename _trigger_backend () to _connect_backend ()
#
# Revision 1.10  2009/08/24 18:52:53  root
# bugfix: lsusb test fixed, ohci_hcd added
#
# Revision 1.9  2009/08/23 23:50:35  root
# bugfix with domain not started
#
# Revision 1.8  2009/08/23 23:14:05  root
# use -t to trigger domain needed
#
# Revision 1.7  2009/08/23 21:41:27  root
# optimzed trigger_backend
#
# Revision 1.6  2009/08/23 21:01:21  root
# read USB-Ports from $CONFIG
#
# 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 2>/dev/null)
if [ ! $? ]; then
    echo "Error: Missing command 'lsusb', please install usbutils"
    exit 1
fi
XSREAD=/usr/bin/xenstore-read
XSWRITE=/usr/bin/xenstore-write
XSCHMOD=/usr/bin/xenstore-chmod
set -e
LSUSB=$(echo "$LSUSB" | grep -v '0000:0000')
usage ()
{
                # $(basename $0) -l | -r
                # $(basename $0) -x <usb-port>:<domain>:0:<vport>
#    -r            # read PVUSB hotplug rules
#    -x            # delete PVUSB hotplug rule (use copy/paste from -r list)
  cat <<-EOT
        usage:  $(basename $0) -b [-t] | -i
                $(basename $0) -s <domain> -a [ -t ]
                $(basename $0) -d <device_id> -s <domain> [-c <comment>] -w [ -t ]
                $(basename $0) -u <usb-port> -s <domain> [-c <comment>] -w [ -t ]
                $(basename $0) -l
    ------------
    -a            # activate PVUSB (for -s <domain>)
    -b            # boot/initialise PVUSB with hotplug rules ($CONFIG_FILE)
    -i            # initialize PVUSB without hotplug rules ($CONFIG_FILE)
    -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' (use 'lsusb' to get the ID)
    -c <comment>  # e.g. "Canon IP4000 Printer"
    -l            # list grabbed PVUSB Devices
    -w            # write/activate PVUSB hotplug rule
    -t            # try to trigger all domains (per ssh) to init PVUSB
    -q            # be quiet
    -D            # Debug option (set -x)
EOT
}
init ()
{
    NUM_PORTS=8        # Max 16 PVUSB ports.
    VUSB_BUS=0          # virtual USB Bus in <domain> (we use usb bus 0)
    CONFIG_FILE=/etc/xen/pvusb.conf
    [ -e $CONFIG_FILE ] || cat >$CONFIG_FILE <<-EOT
        # Configfile for pvusb
        # 'pvusb -b' connects <Device_Id> / <USB-Port> to <Domain>
        # 'pvusb -i' initializes <Domain> for PVUSB
        # <Device_Id>  <Domain> <Comment>
        # 1234:5678    server  USB-Printer on an USB-Port
        # <USB-Port>  <Domain> <Comment>
        # 3-2          server  Any Device on Port 3-2
        # <Device_Id>  <Domain> <Comment>
        # 0000:0000    server  initialize 'server' for PVUSB
EOT
    CONFIG=$(cat $CONFIG_FILE | sed -e 's/#.*$//' -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e '/^$/ d' -e '/^[[:graph:]]*$/ d')
}
#
# 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)
    # check if xenstore is already initialized
    [ -e /sys/bus/xen-backend/drivers/vusb/vusb-$dom_id-$vusb_bus ] && return
    # check if PVUSB is already initialized
    [ -e /sys/bus/xen-backend/drivers/vusb ] || pvusb_init_backend
    # 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 USB Spec version field.
    $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/usb-ver 2
    # 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 ""
    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/usb-ver 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 r0
    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
    # load usb (backend) modules
    modprobe usbbk
}
pvusb_connect_backend ()
{
    # connect USB devices to backend (and restart udevd afterwards)
    # stop udevd fetching events before the backend driver
    udevadm control --stop_exec_queue
    # XXX: find better way to connect USB devices dynamically!!!
    rmmod uhci_hcd ehci_hcd ohci_hcd 2>/dev/null || true
    modprobe -a uhci_hcd ehci_hcd ohci_hcd || true
    # 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
    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
    # 1) initialise paravirtualized USB Support for dom_id
    pvusb_init_xenstore $dom_id $VUSB_BUS
    # get the next free USB Port in <domain>
    vusb_port=$(get_free_vusb_port $dom_id)
    # 2) Write the hotplug-rule to xenstore
    $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port/$vusb_port $usb_port
    # tell me what happened
    if [ -z "$QUIET" ]; then
        actual_vport=$($XSREAD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port/$vusb_port || true)
        echo "xen PVUSB Rule written: $actual_vport $comment on domain $dom_name ($dom_id)"
    fi
}
get_free_vusb_port ()
{
    # get new vusb_port between 2 .. $NUM_PORTS
    dom_id=$1
    for ((i=1; $i<=$NUM_PORTS; i++)); do
        vport=$($XSREAD /local/domain/0/backend/vusb/$dom_id/0/port/$i || true)
        [ -z "$vport" ] && { echo "$i"; return; }
    done
    echo "Error: no virtual USB-Port free for $dom_id" >&2
    exit 1
}
get_usb_port ()
{
    # find out where USB-Device is connected
    usb_dev=$1
    usb_port=""
    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 || true); do
        adr=$(cat /sys/bus/usb/devices/$port/devnum)
        if [ "$adr" = "$usb_adr" ]; then
            echo "$port"
            return
        fi
    done
    echo "Error: no USB-Port found for $usb_dev" >&2
}
pvusb_init_domains_from_configfile ()
{
    domains=$(echo "$CONFIG" | awk '/^0000:0000 / {print $2}')
    for domain in $domains; do
        dom_id=$(xm domid $domain || continue)
        [ -n "$dom_id" ] || continue
        pvusb_init_xenstore $dom_id $VUSB_BUS
        # remember domain to be triggered
        PVUSB_DOMAINS=$(cat <<-EOT | sort -u
                $PVUSB_DOMAINS
                $domain)
    done
}
pvusb_write_defined_ports_from_configfile ()
{
    # $CONFIG: where to connect the USB-Ports
    # ---------------------------------------
    ports=$(echo "$CONFIG" | awk '/^[0-9]-[0-9] / {print $1}')
    for usb_port in $ports; do
        # read static definitions from $CONFIG
        pvusb_conf=$(echo "$CONFIG" | grep $usb_port | tail -1)
        if [ -n "$pvusb_conf" ]; then
            domain=$(echo $pvusb_conf | awk '{print $2}')
            comment=$(echo $pvusb_conf | cut -d\  -f3-)
            [ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue
        else
            continue
        fi
        # 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_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
     # get all connected USB devices
     # get all connected USB devices
     usb_devices=$(lsusb | grep -v '0000:0000' | awk '{print $6}')
     usb_devices=$(echo "$LSUSB" | awk '{print $6}')


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


     # PVUSB initialising / prerequisits
     # 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}')"
    pvusb_init


     # PVUSB write backend rules
     for usb_dev in $usb_devices; do
    # -------------------------
 
    pvusb_write_connected_devices_static "$usb_devices"
        # where to connect my usb devices to?
        # read static definitions from $CONFIG
 
        pvusb_conf=$(echo "$CONFIG" | grep $usb_dev | tail -1)
        if [ -n "$pvusb_conf" ]; then
            domain=$(echo $pvusb_conf | awk '{print $2}')
            comment=$(echo $pvusb_conf | cut -d\  -f3-)
            # skip if <domain> isn't activ
            [ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue
        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 || true); do
            adr=$(cat /sys/bus/usb/devices/$port/devnum)
            if [ "$adr" = "$usb_adr" ]; then
                usb_port=$port
                break
            fi
        done
        if [ -z "$usb_port" ]; then
            echo "Error: No USB Port found for $usb_dev"
            continue
        fi
        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
}
}


Zeile 253: Zeile 966:
{
{
     # PVUSB trigger for all relevant domains
     # PVUSB trigger for all relevant domains
    # --------------------------------------
    [ -n "$PVUSB" ] || return
    # tell PV domain to reload USB
     # XXX: better way to trigger domU?
     # XXX: better way to trigger domU?
     for server in $(echo "$1" | sort -u); do
     for domain in $(echo "$1" | sort -u); do
         ssh $server "[ -n \"\$(lsusb|grep -v '0000:0000')\" ] || exit 0 ;
         ssh $domain "[ -n \"\$(lsusb || true)\" ] && exit 0 ;
                     rmmod xen_hcd usbcore ;
                     rmmod xen_hcd usbcore || true ;
                     modprobe xen_hcd
                     modprobe xen_hcd
                     "
                     " || true
     done
     done
}
}
Zeile 270: Zeile 979:
     # tell me what happened
     # tell me what happened
     # ---------------------
     # ---------------------
     pvusb_grabbed="$(cat /sys/bus/usb/drivers/usbback/grabbed_devices)"
     for vusb_dev in /sys/bus/xen-backend/drivers/vusb/vusb-*-*; do
    for pvusb in $pvusb_grabbed; do
         dom_id=$(basename "$vusb_dev" | cut -d- -f2)
         usb_port=$(echo $pvusb| awk -F: '{print $1}')
        [ "$dom_id" == '*' ] && break
        domain=$(cat /sys/bus/usb/drivers/usbback/vports | awk -F: "/$usb_port/"' {print $2}')
        for ((i=1; $i<=$NUM_PORTS; i++)); do
        dev_id="$(cat /sys/bus/usb/devices/$usb_port/idVendor)"
            port=$($XSREAD /local/domain/0/backend/vusb/$dom_id/0/port/$i || true)
        dev_id="$dev_id:$(cat /sys/bus/usb/devices/$usb_port/idProduct)"
            if [ -n "$port" ]; then
        product=$(lsusb | grep $dev_id | cut -d\  -f6-)
                usb_port=$port
        echo "PVUSB: $usb_port on `xm domname $domain` ($domain) $product"
                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 2>/dev/null || echo "<inactiv>") ($dom_id) $product"
            fi
        done
     done
     done
    #pvusb_grabbed=$(ls /sys/bus/xen-backend/drivers/vusb/vusb-*-*)
    #for pvusb in $pvusb_grabbed; do
    #    usb_port=$(basename $pvusb | awk -F: '{print $1}')
    #    dom_id=$(cat /sys/bus/usb/drivers/usbback/port_ids | 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 2>/dev/null || echo "<inactiv>") ($dom_id) $product"
    #done
}
}


Zeile 286: Zeile 1.011:
init
init


while getopts ":bc:d:hs:lqu:w" opt; do
#while getopts ":abc:d:Dhilqrs:tu:wx:" opt; do
while getopts ":abc:d:Dhilqs:tu:w:" opt; do
   case $opt in
   case $opt in
     b) # boot host with static defined rules
     a) # activate PVUSB for <domain> without any rules
       pvusb_boot_host
       dom_id=$(xm domid $domain)
       pvusb_setup
       pvusb_init_xenstore $dom_id $VUSB_BUS
      pvusb_trigger $PVUSB_DOMAINS
      sleep 1
       ;;
       ;;
     c) # COMMENT (Canon IP4000)
    b) # boot host with setup rules in $CONFIG
      pvusb_init_backend
      pvusb_init_domains_from_configfile
      pvusb_write_connected_devices_from_configfile
      pvusb_write_defined_ports_from_configfile
      pvusb_connect_backend
      ;;
    i) # initialise PVUSB without any rules
      pvusb_init_backend
      pvusb_init_domains_from_configfile
      pvusb_connect_backend
      ;;
     c) # comment  e.g. Canon IP4000
       comment=$OPTARG
       comment=$OPTARG
       ;;
       ;;
Zeile 300: Zeile 1.036:
       usb_port=$(get_usb_port $OPTARG)
       usb_port=$(get_usb_port $OPTARG)
       ;;
       ;;
     s) # Server Domain name od id
    h) usage
       domain=$OPTARG
      ;;
    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)
     u) # USB-PORT (3-2)
Zeile 307: Zeile 1.057:
       ;;
       ;;
     w) # write rule PVUSB
     w) # write rule PVUSB
       pvusb_init
       pvusb_write_rule $domain $usb_port "$comment"
      pvusb_port $domain $usb_port "$comment"
      pvusb_setup
      pvusb_trigger $PVUSB_DOMAINS
      ;;
    l) # list (default=on) PVUSB Ports
       LIST_PVUSB=1
       LIST_PVUSB=1
       ;;
       ;;
     q) # don't list PVUSB Ports
     x) # delete PVUSB rule
       LIST_PVUSB=0
       #echo "$OPTARG" > /sys/bus/usb/drivers/usbback/remove_vport || true
       ;;
       ;;
     h)
     D) set -x
      usage
       ;;
       ;;
     \?)
     \?)
Zeile 327: Zeile 1.071:
done
done


[ $LIST_PVUSB -gt 0 ] && pvusb_list
[ "$LIST_PVUSB" = "1" ] && pvusb_list
</pre>
</pre>

Aktuelle Version vom 26. Juni 2010, 19:59 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).

Die USB DeviceIDs (z.B. '04a9:1093') kann man mit dem Komamndo lsusb ermitteln. Die USB-Ports (z.B. '3-2') werden beim Anstecken der Devices auf der Systemkonsole (Dom0) angezeigt.

File /etc/xen/pvusb.conf

# Configfile for pvusb
# Dev_Id    <domain> <Comment>
# USBPort   <domain> <Comment>
# 0000:0000 <domain> <Comment>
04a9:1093   srv      Canon Printer IP4000
5-1         dmz      Anything on USB Port 5-1
0000:0000   vm01     initialize 'vm01' for PVUSB

File /etc/rc.local

Für die Option -t ("Trigger Domain") muss SSH Access per SSH-Keys funktionieren, da mit ssh <domain> <Befehle> versucht wird, Remote-Kommandos innerhalb der Domain auszuführen.

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

Beispiele für pvusb

m450:~# pvusb -h
usage:  pvusb -b [-t] | -i
        pvusb -s <domain> -a [ -t ]
        pvusb -d <device_id> -s <domain> [-c <comment>] -w [ -t ]
        pvusb -u <usb-port> -s <domain> [-c <comment>] -w [ -t ]
        pvusb -l | -r
        pvusb -x <usb-port>:<domain>:0:<vport>
    ------------
    -a            # activate PVUSB (for -s <domain>)
    -b            # boot/initialise PVUSB with hotplug rules (/etc/xen/pvusb.conf)
    -i            # initialize PVUSB without hotplug rules (/etc/xen/pvusb.conf)
    -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' (use 'lsusb' to get the ID)
    -c <comment>  # e.g. "Canon IP4000 Printer"
    -l            # list grabbed PVUSB Devices
    -r            # read PVUSB hotplug rules
    -w            # write/activate PVUSB hotplug rule
    -x            # delete PVUSB hotplug rule (use copy/paste from -r list)
    -t            # try to trigger all domains (per ssh) to init PVUSB
    -q            # be quiet
    -D            # Debug option (set -x)

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

Dieses Skript funktioniert nicht mit Xen 3.4.3, wegen Änderungen im xenstore. Ab XEN 4.0 kann im Konfigfile die Option vusb = [ 'usbver=2, numports=8, port_1=5-8' ] verwendet werden. Skript für XEN 3.4.3 siehe weiter unten!

Das Skript /usr/local/sbin/pvusb für Xen 3.4.2

#!/bin/sh
#
# paravirtualized USB Support (XEN 3.4.2)
#
# Version: $Revision: 1.15 $
# Datum:   $Date: 2009/08/31 07:28:49 $
#
# Author:  neobiker
#
# $Log: pvusb,v $
# Revision 1.15  2009/08/31 07:28:49  root
# init_xenstore (): call init_backend () if needed
#
# Revision 1.14  2009/08/26 17:15:17  root
# updated usage () and some info's
#
# Revision 1.13  2009/08/26 07:12:35  root
# bugfix: get_free_vusb_port ()
# check if xenstore is initialized
#
# Revision 1.12  2009/08/25 20:05:43  root
# some optimization and error handling
#
# Revision 1.11  2009/08/24 19:01:36  root
# rename _trigger_backend () to _connect_backend ()
#
# Revision 1.10  2009/08/24 18:52:53  root
# bugfix: lsusb test fixed, ohci_hcd added
#
# Revision 1.9  2009/08/23 23:50:35  root
# bugfix with domain not started
#
# Revision 1.8  2009/08/23 23:14:05  root
# use -t to trigger domain needed
#
# Revision 1.7  2009/08/23 21:41:27  root
# optimzed trigger_backend
#
# Revision 1.6  2009/08/23 21:01:21  root
# read USB-Ports from $CONFIG
#
# 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 2>/dev/null | grep -v '0000:0000' || echo "Error")
if [ "$LSUSB" = "Error" ]; then
    echo "Error: Missing command 'lsusb', please install usbutils"
    exit 1
fi

set -e

usage ()
{
  cat <<-EOT
        usage:  $(basename $0) -b [-t] | -i
                $(basename $0) -s <domain> -a [ -t ]
                $(basename $0) -d <device_id> -s <domain> [-c <comment>] -w [ -t ]
                $(basename $0) -u <usb-port> -s <domain> [-c <comment>] -w [ -t ]
                $(basename $0) -l | -r
                $(basename $0) -x <usb-port>:<domain>:0:<vport>
    ------------
    -a            # activate PVUSB (for -s <domain>)
    -b            # boot/initialise PVUSB with hotplug rules ($CONFIG_FILE)
    -i            # initialize PVUSB without hotplug rules ($CONFIG_FILE)
    -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' (use 'lsusb' to get the ID)
    -c <comment>  # e.g. "Canon IP4000 Printer"
    -l            # list grabbed PVUSB Devices
    -r            # read PVUSB hotplug rules
    -w            # write/activate PVUSB hotplug rule
    -x            # delete PVUSB hotplug rule (use copy/paste from -r list)
    -t            # try to trigger all domains (per ssh) to init PVUSB
    -q            # be quiet
    -D            # Debug option (set -x)
EOT
}

init ()
{
    NUM_PORTS=8         # Max 16 PVUSB ports.
    VUSB_BUS=0          # virtual USB Bus in <domain> (we use always usb bus 0)

    CONFIG_FILE=/etc/xen/pvusb.conf

    [ -e $CONFIG_FILE ] || cat >$CONFIG_FILE <<-EOT
        # Configfile for pvusb
        # 'pvusb -b' connects <Device_Id> / <USB-Port> to <Domain>
        # 'pvusb -i' initializes <Domain> for PVUSB

        # <Device_Id>  <Domain> <Comment>
        # 1234:5678    server   USB-Printer on an USB-Port

        # <USB-Port>   <Domain> <Comment>
        # 3-2          server   Any Device on Port 3-2

        # <Device_Id>  <Domain> <Comment>
        # 0000:0000    server   initialize 'server' for PVUSB
EOT

    CONFIG=$(cat $CONFIG_FILE | sed -e 's/#.*$//' -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e '/^$/ d' -e '/^[[:graph:]]*$/ d')
}

#
# 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)

    # check if xenstore is already initialized
    [ -e /sys/devices/xen-backend/vusb-$dom_id-$vusb_bus ] && return

    # check if PVUSB is already initialized
    [ -e /sys/bus/xen-backend/drivers/vusb ] || pvusb_init_backend

    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

    # load usb (backend) modules
    modprobe usbbk
}

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

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

    # XXX: find better way to connect USB devices dynamically!!!
    rmmod uhci_hcd ehci_hcd ohci_hcd 2>/dev/null || true
    modprobe -a uhci_hcd ehci_hcd ohci_hcd || true

    # 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

    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

    # get the next free USB Port in <domain>
    vusb_port=$(get_free_vusb_port $dom_id)

    # 1) initialise paravirtualized USB Support for dom_id
    pvusb_init_xenstore $dom_id $VUSB_BUS

    # 2a) 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

    # 2b) 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_free_vusb_port ()
{
    # get new vusb_port between 2 .. $NUM_PORTS
    dom_id=$1
    vports=$(cat /sys/bus/usb/drivers/usbback/vports | awk -v FS=: "/^.*:$dom_id:.*:.*/ {print \$4}")
    if [ -z "$vports" ]; then
        echo "2"
        return
    else
        for ((i=2; $i<=$NUM_PORTS; i++)); do
           for vport in $vports; do
               [ "$vport" -eq $i ] && break
           done
           [ $vport -ne $i ] && { echo "$i"; return; }
        done
    fi
    echo "Error: no virtual USB-Port free for $dom_id" >&2
    exit 1
}

get_usb_port ()
{
    # find out where USB-Device is connected
    usb_dev=$1
    usb_port=""
    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 || true); do
        adr=$(cat /sys/bus/usb/devices/$port/devnum)
        if [ "$adr" = "$usb_adr" ]; then
            echo "$port"
            return
        fi
    done
    echo "Error: no USB-Port found for $usb_dev" >&2
}

pvusb_init_domains_from_configfile ()
{
    domains=$(echo "$CONFIG" | awk '/^0000:0000 / {print $2}')

    for domain in $domains; do
        dom_id=$(xm domid $domain || continue)

        [ -n "$dom_id" ] || continue
        pvusb_init_xenstore $dom_id $VUSB_BUS

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

pvusb_write_defined_ports_from_configfile ()
{
    # $CONFIG: where to connect the USB-Ports
    # ---------------------------------------
    ports=$(echo "$CONFIG" | awk '/^[0-9]-[0-9] / {print $1}')

    for usb_port in $ports; do

        # read static definitions from $CONFIG
        pvusb_conf=$(echo "$CONFIG" | grep $usb_port | tail -1)
        if [ -n "$pvusb_conf" ]; then
            domain=$(echo $pvusb_conf | awk '{print $2}')
            comment=$(echo $pvusb_conf | cut -d\  -f3-)
            [ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue

        else
            continue
        fi

        # 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_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

    # 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 connected USB Devices found."
        return
    fi

    # 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 $usb_devices; do

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

        pvusb_conf=$(echo "$CONFIG" | grep $usb_dev | tail -1)
        if [ -n "$pvusb_conf" ]; then
            domain=$(echo $pvusb_conf | awk '{print $2}')
            comment=$(echo $pvusb_conf | cut -d\  -f3-)
            # skip if <domain> isn't activ
            [ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue
        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 || true); do
            adr=$(cat /sys/bus/usb/devices/$port/devnum)
            if [ "$adr" = "$usb_adr" ]; then
                usb_port=$port
                break
            fi
        done
        if [ -z "$usb_port" ]; then
            echo "Error: No USB Port found for $usb_dev"
            continue
        fi
        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_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 || true ;
                     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 2>/dev/null || echo "<inactiv>") ($dom_id) $product"
    done
}

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

while getopts ":abc:d:Dhilqrs:tu:wx:" opt; do
  case $opt in
    a) # activate PVUSB for <domain> without any rules
      dom_id=$(xm domid $domain)
      pvusb_init_xenstore $dom_id $VUSB_BUS
      ;;
    b) # boot host with setup rules in $CONFIG
      pvusb_init_backend
      pvusb_init_domains_from_configfile
      pvusb_write_connected_devices_from_configfile
      pvusb_write_defined_ports_from_configfile
      pvusb_connect_backend
      ;;
    i) # initialise PVUSB without any rules
      pvusb_init_backend
      pvusb_init_domains_from_configfile
      pvusb_connect_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_write_rule $domain $usb_port "$comment"
      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

Das Skript für XEN 3.4.3

#!/bin/sh
#
# paravirtualized USB Support (XEN 3.4.3)
#
# Version: $Revision: 1.16 $
# Datum:   $Date: 2010/06/26 15:42:21 $
#
# Author:  neobiker
#
# $Log: pvusb,v $
# Revision 1.16  2010/06/26 15:42:21  root
# Changes for XEN 3.4.3
#
# Revision 1.15  2009/08/31 07:28:49  root
# init_xenstore (): call init_backend () if needed
#
# Revision 1.14  2009/08/26 17:15:17  root
# updated usage () and some info's
#
# Revision 1.13  2009/08/26 07:12:35  root
# bugfix: get_free_vusb_port ()
# check if xenstore is initialized
#
# Revision 1.12  2009/08/25 20:05:43  root
# some optimization and error handling
#
# Revision 1.11  2009/08/24 19:01:36  root
# rename _trigger_backend () to _connect_backend ()
#
# Revision 1.10  2009/08/24 18:52:53  root
# bugfix: lsusb test fixed, ohci_hcd added
#
# Revision 1.9  2009/08/23 23:50:35  root
# bugfix with domain not started
#
# Revision 1.8  2009/08/23 23:14:05  root
# use -t to trigger domain needed
#
# Revision 1.7  2009/08/23 21:41:27  root
# optimzed trigger_backend
#
# Revision 1.6  2009/08/23 21:01:21  root
# read USB-Ports from $CONFIG
#
# 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 2>/dev/null)
if [ ! $? ]; then
    echo "Error: Missing command 'lsusb', please install usbutils"
    exit 1
fi

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

set -e

LSUSB=$(echo "$LSUSB" | grep -v '0000:0000')

usage ()
{
                # $(basename $0) -l | -r
                # $(basename $0) -x <usb-port>:<domain>:0:<vport>
#    -r            # read PVUSB hotplug rules
#    -x            # delete PVUSB hotplug rule (use copy/paste from -r list)

  cat <<-EOT
        usage:  $(basename $0) -b [-t] | -i
                $(basename $0) -s <domain> -a [ -t ]
                $(basename $0) -d <device_id> -s <domain> [-c <comment>] -w [ -t ]
                $(basename $0) -u <usb-port> -s <domain> [-c <comment>] -w [ -t ]
                $(basename $0) -l
    ------------
    -a            # activate PVUSB (for -s <domain>)
    -b            # boot/initialise PVUSB with hotplug rules ($CONFIG_FILE)
    -i            # initialize PVUSB without hotplug rules ($CONFIG_FILE)
    -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' (use 'lsusb' to get the ID)
    -c <comment>  # e.g. "Canon IP4000 Printer"
    -l            # list grabbed PVUSB Devices
    -w            # write/activate PVUSB hotplug rule
    -t            # try to trigger all domains (per ssh) to init PVUSB
    -q            # be quiet
    -D            # Debug option (set -x)
EOT
}

init ()
{
    NUM_PORTS=8         # Max 16 PVUSB ports.
    VUSB_BUS=0          # virtual USB Bus in <domain> (we use usb bus 0)

    CONFIG_FILE=/etc/xen/pvusb.conf

    [ -e $CONFIG_FILE ] || cat >$CONFIG_FILE <<-EOT
        # Configfile for pvusb
        # 'pvusb -b' connects <Device_Id> / <USB-Port> to <Domain>
        # 'pvusb -i' initializes <Domain> for PVUSB

        # <Device_Id>  <Domain> <Comment>
        # 1234:5678    server   USB-Printer on an USB-Port

        # <USB-Port>   <Domain> <Comment>
        # 3-2          server   Any Device on Port 3-2

        # <Device_Id>  <Domain> <Comment>
        # 0000:0000    server   initialize 'server' for PVUSB
EOT

    CONFIG=$(cat $CONFIG_FILE | sed -e 's/#.*$//' -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' -e '/^$/ d' -e '/^[[:graph:]]*$/ d')
}

#
# 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)

    # check if xenstore is already initialized
    [ -e /sys/bus/xen-backend/drivers/vusb/vusb-$dom_id-$vusb_bus ] && return

    # check if PVUSB is already initialized
    [ -e /sys/bus/xen-backend/drivers/vusb ] || pvusb_init_backend

    # 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 USB Spec version field.
    $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/usb-ver 2

    # 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 ""
    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/usb-ver 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 r0
    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

    # load usb (backend) modules
    modprobe usbbk
}

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

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

    # XXX: find better way to connect USB devices dynamically!!!
    rmmod uhci_hcd ehci_hcd ohci_hcd 2>/dev/null || true
    modprobe -a uhci_hcd ehci_hcd ohci_hcd || true

    # 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

    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

    # 1) initialise paravirtualized USB Support for dom_id
    pvusb_init_xenstore $dom_id $VUSB_BUS

    # get the next free USB Port in <domain>
    vusb_port=$(get_free_vusb_port $dom_id)

    # 2) Write the hotplug-rule to xenstore
    $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port/$vusb_port $usb_port

    # tell me what happened
    if [ -z "$QUIET" ]; then
        actual_vport=$($XSREAD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port/$vusb_port || true)
        echo "xen PVUSB Rule written: $actual_vport $comment on domain $dom_name ($dom_id)"
    fi
}

get_free_vusb_port ()
{
    # get new vusb_port between 2 .. $NUM_PORTS
    dom_id=$1

    for ((i=1; $i<=$NUM_PORTS; i++)); do
        vport=$($XSREAD /local/domain/0/backend/vusb/$dom_id/0/port/$i || true)
        [ -z "$vport" ] && { echo "$i"; return; }
    done

    echo "Error: no virtual USB-Port free for $dom_id" >&2
    exit 1
}

get_usb_port ()
{
    # find out where USB-Device is connected
    usb_dev=$1
    usb_port=""
    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 || true); do
        adr=$(cat /sys/bus/usb/devices/$port/devnum)
        if [ "$adr" = "$usb_adr" ]; then
            echo "$port"
            return
        fi
    done
    echo "Error: no USB-Port found for $usb_dev" >&2
}

pvusb_init_domains_from_configfile ()
{
    domains=$(echo "$CONFIG" | awk '/^0000:0000 / {print $2}')

    for domain in $domains; do
        dom_id=$(xm domid $domain || continue)

        [ -n "$dom_id" ] || continue
        pvusb_init_xenstore $dom_id $VUSB_BUS

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

pvusb_write_defined_ports_from_configfile ()
{
    # $CONFIG: where to connect the USB-Ports
    # ---------------------------------------
    ports=$(echo "$CONFIG" | awk '/^[0-9]-[0-9] / {print $1}')

    for usb_port in $ports; do

        # read static definitions from $CONFIG
        pvusb_conf=$(echo "$CONFIG" | grep $usb_port | tail -1)
        if [ -n "$pvusb_conf" ]; then
            domain=$(echo $pvusb_conf | awk '{print $2}')
            comment=$(echo $pvusb_conf | cut -d\  -f3-)
            [ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue

        else
            continue
        fi

        # 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_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

    # get all connected USB devices
    usb_devices=$(echo "$LSUSB" | awk '{print $6}')

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

    # 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 $usb_devices; do

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

        pvusb_conf=$(echo "$CONFIG" | grep $usb_dev | tail -1)
        if [ -n "$pvusb_conf" ]; then
            domain=$(echo $pvusb_conf | awk '{print $2}')
            comment=$(echo $pvusb_conf | cut -d\  -f3-)
            # skip if <domain> isn't activ
            [ -z "$(xm domname $domain 2>/dev/null || true)" ] && continue
        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 || true); do
            adr=$(cat /sys/bus/usb/devices/$port/devnum)
            if [ "$adr" = "$usb_adr" ]; then
                usb_port=$port
                break
            fi
        done
        if [ -z "$usb_port" ]; then
            echo "Error: No USB Port found for $usb_dev"
            continue
        fi
        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_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 || true ;
                     modprobe xen_hcd
                    " || true
    done
}

pvusb_list ()
{
    # tell me what happened
    # ---------------------
    for vusb_dev in /sys/bus/xen-backend/drivers/vusb/vusb-*-*; do
        dom_id=$(basename "$vusb_dev" | cut -d- -f2)
        [ "$dom_id" == '*' ] && break
        for ((i=1; $i<=$NUM_PORTS; i++)); do
            port=$($XSREAD /local/domain/0/backend/vusb/$dom_id/0/port/$i || true)
            if [ -n "$port" ]; then
                usb_port=$port
                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 2>/dev/null || echo "<inactiv>") ($dom_id) $product"
            fi
        done
    done
    #pvusb_grabbed=$(ls /sys/bus/xen-backend/drivers/vusb/vusb-*-*)

    #for pvusb in $pvusb_grabbed; do
    #    usb_port=$(basename $pvusb | awk -F: '{print $1}')
    #    dom_id=$(cat /sys/bus/usb/drivers/usbback/port_ids | 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 2>/dev/null || echo "<inactiv>") ($dom_id) $product"
    #done
}

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

#while getopts ":abc:d:Dhilqrs:tu:wx:" opt; do
while getopts ":abc:d:Dhilqs:tu:w:" opt; do
  case $opt in
    a) # activate PVUSB for <domain> without any rules
      dom_id=$(xm domid $domain)
      pvusb_init_xenstore $dom_id $VUSB_BUS
      ;;
    b) # boot host with setup rules in $CONFIG
      pvusb_init_backend
      pvusb_init_domains_from_configfile
      pvusb_write_connected_devices_from_configfile
      pvusb_write_defined_ports_from_configfile
      pvusb_connect_backend
      ;;
    i) # initialise PVUSB without any rules
      pvusb_init_backend
      pvusb_init_domains_from_configfile
      pvusb_connect_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_write_rule $domain $usb_port "$comment"
      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