XEN PVUSB: Unterschied zwischen den Versionen
Keine Bearbeitungszusammenfassung |
Keine Bearbeitungszusammenfassung |
||
Zeile 61: | Zeile 61: | ||
# paravirtualized USB Support | # paravirtualized USB Support | ||
# | # | ||
# Version: $Revision: 1. | # Version: $Revision: 1.4 $ | ||
# Datum: $Date: 2009/08/ | # Datum: $Date: 2009/08/23 17:06:54 $ | ||
# | # | ||
# Author: neobiker | # Author: neobiker | ||
# | # | ||
# $Log: pvusb,v $ | # $Log: pvusb,v $ | ||
# Revision 1.4 2009/08/23 17:06:54 root | |||
# optimization and code readability | |||
# | |||
# Revision 1.3 2009/08/22 19:35:40 root | # Revision 1.3 2009/08/22 19:35:40 root | ||
# bugfix convert dom_id+dom_nam | # bugfix convert dom_id+dom_nam | ||
Zeile 76: | Zeile 79: | ||
# Initial revision | # 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 -e | ||
#set -x | #set -x | ||
usage () | usage () | ||
Zeile 92: | Zeile 97: | ||
------------ | ------------ | ||
-b # boot host with static defined PVUSB rules | -b # boot host with static defined PVUSB rules | ||
-s domain # server | -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" | ||
-d device_id # USB device_id e.g. "0912:1234" | -d device_id # USB device_id e.g. "0912:1234" | ||
-c comment # e.g. "Canon IP4000" | -c comment # e.g. "Canon IP4000" | ||
-l # list | -l # list grabbed PVUSB Devices | ||
-q # | -q # be quiet | ||
-r # list PVUSB rules | -r # list PVUSB rules | ||
-w # write/activate PVUSB rule | -w # write/activate PVUSB rule | ||
Zeile 106: | Zeile 111: | ||
init () | init () | ||
{ | { | ||
PVUSB_INIT=0 | PVUSB_INIT=0 # only a flag | ||
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 | ||
# Configfile for pvusb | # Configfile for pvusb | ||
# Device_Id Domain Comment | # 'pvusb -b' connects Device_Id to Domain | ||
# | # Device_Id Domain Comment | ||
# 1234:5678 server USB-Printer | |||
EOT | EOT | ||
} | } | ||
Zeile 126: | Zeile 134: | ||
# based on init_xs.sh by Noboru Iwamatsu | # based on init_xs.sh by Noboru Iwamatsu | ||
dom_id=$1 | |||
vusb_bus=$2 # vusb_bus (typical 0) | |||
XSWRITE=/usr/bin/xenstore-write | XSWRITE=/usr/bin/xenstore-write | ||
Zeile 136: | Zeile 141: | ||
# Write backend information into the location that frontend look for. | # Write backend information into the location that frontend look for. | ||
$XSWRITE /local/domain/$ | $XSWRITE /local/domain/$dom_id/device/vusb/$vusb_bus/backend-id 0 | ||
$XSWRITE /local/domain/$ | $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. | # Write frontend information into the location that backend look for. | ||
$XSWRITE /local/domain/0/backend/ | $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend-id $dom_id | ||
$XSWRITE /local/domain/0/backend/ | $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend \ | ||
/local/domain/$dom_id/device/vusb/$vusb_bus | |||
# Write virtual root hub field. | # Write virtual root hub field. | ||
$XSWRITE /local/domain/0/backend/ | $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/ | $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/port-$i "0" | ||
done | done | ||
# Set permission | # Set permission | ||
$XSCHMOD /local/domain/$ | $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus n$dom_id r0 | ||
$XSCHMOD /local/domain/$ | $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/backend-id n$dom_id r0 | ||
$XSCHMOD /local/domain/$ | $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/backend n$dom_id r0 | ||
$XSCHMOD /local/domain/0/backend/ | $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus n0 r$dom_id | ||
$XSCHMOD /local/domain/0/backend/ | $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend-id n0 r$dom_id | ||
$XSCHMOD /local/domain/0/backend/ | $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/frontend n0 r$dom_id | ||
$XSCHMOD /local/domain/0/backend/ | $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/ | $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/$ | $XSWRITE /local/domain/$dom_id/device/vusb/$vusb_bus/state 1 | ||
$XSCHMOD /local/domain/$ | $XSCHMOD /local/domain/$dom_id/device/vusb/$vusb_bus/state n$dom_id r0 | ||
$XSWRITE /local/domain/0/backend/ | $XSWRITE /local/domain/0/backend/vusb/$dom_id/$vusb_bus/state 1 | ||
$XSCHMOD /local/domain/0/backend/ | $XSCHMOD /local/domain/0/backend/vusb/$dom_id/$vusb_bus/state n0 r$dom_id | ||
} | } | ||
pvusb_init_backend () | |||
{ | { | ||
# initialise backend only once | |||
[ "$PVUSB_INIT" ] || return | [ "$PVUSB_INIT" ] || 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 188: | Zeile 193: | ||
# load usb (backend) modules | # load usb (backend) modules | ||
modprobe usbbk | modprobe usbbk | ||
# remember that pvusb is initialised | |||
echo $$ > $PVUSB_PID | |||
PVUSB_INIT=1 | |||
} | } | ||
pvusb_setup_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? | |||
# call once the workaraound to remove Hostcontroller completly | |||
# XXX: oterhwise usbbk is already working? | |||
if [ $(cat $PVUSB_PID) -le $$ ]; then | |||
# 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 201: | Zeile 219: | ||
} | } | ||
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 | comment=$3 # a name for usb device | ||
vusb_bus=0 # virtual USB Bus in domain (we use always usb bus 0) | vusb_bus=0 # virtual USB Bus in domain (we use always usb bus 0) | ||
if [ -z "$ | if [ -z "$domain" ]; then | ||
echo "missing option -s < | echo "missing option -s <domain>" | ||
return | return | ||
fi | fi | ||
if [ -z "$ | if [ -z "$usb_port" ]; then | ||
echo "missing option -u <usb_port>" | echo "missing option -u <usb_port>" | ||
return | return | ||
fi | fi | ||
# get new | if [ "$domain" = "$(echo $domain | tr -d [:alpha:])" ]; then | ||
dom_name=$(xm domname $domain) | |||
if [ -z "$ | dom_id=$domain | ||
else | |||
dom_name=$domain | |||
dom_id=$(xm domid $domain) | |||
fi | |||
# get new vusb_port between 2 .. $NUM_PORTS | |||
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 | else | ||
((++ | for ((i=2; $i<=$NUM_PORTS; i++)); do | ||
if [ -z "$(echo "$vusb_port" | grep $i)" ]; then | |||
new_id=$i | |||
break | |||
fi | |||
done | |||
fi | fi | ||
vusb_port=$new_id | |||
# initialise paravirtualized USB Support in domain with | # initialise paravirtualized USB Support in domain with vusb bus 0 | ||
pvusb_init_xenstore $dom_id $vusb_bus | pvusb_init_xenstore $dom_id $vusb_bus | ||
# 2) test and remove existing hotplug-rule | # 2) test and remove existing hotplug-rule | ||
actual_vport=$(cat /sys/bus/usb/drivers/usbback/vports | awk "/$ | 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 | # 2) Write the hotplug-rule through the sysfs interface of the backenend driver | ||
echo "$ | 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 "/$ | 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 | |||
} | } | ||
Zeile 248: | Zeile 281: | ||
# find out where USB-Device is connected | # 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=$( | usb_bus=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$2}') | ||
usb_adr=$( | 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"); do | ||
Zeile 269: | Zeile 302: | ||
devices="$1" | 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}')" | usb_ports="$(/bin/ls -1 /sys/bus/usb/devices/ | awk '/^[0-9]\-[0-9]$/ {print}')" | ||
Zeile 285: | Zeile 319: | ||
# find out where USB-Device is connected | # find out where USB-Device is connected | ||
usb_bus=$( | usb_bus=$(echo "$LSUSB" | grep $usb_dev | awk '{printf "%d",$2}') | ||
usb_adr=$( | 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"); 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 298: | Zeile 332: | ||
# PVUSB write xen backend rules for usb device | # PVUSB write xen backend rules for usb device | ||
# -------------------------------------------- | # -------------------------------------------- | ||
pvusb_write_rule $domain $usb_port "$comment" | |||
# remember domain to be triggered | # remember domain to be triggered | ||
Zeile 307: | Zeile 341: | ||
} | } | ||
pvusb_boot_init () | |||
{ | { | ||
# get all connected USB devices | # get all connected USB devices | ||
usb_devices=$( | usb_devices=$(echo "$LSUSB" | grep -v '0000:0000' | awk '{print $6}') | ||
# ready if no devices are found | # ready if no devices are found | ||
Zeile 320: | Zeile 354: | ||
# PVUSB initialising / prerequisits | # PVUSB initialising / prerequisits | ||
# ------------------ | # ------------------ | ||
[ -e $PVUSB_PID ] && rm $PVUSB_PID | |||
pvusb_init_backend | |||
# PVUSB write backend rules | # PVUSB write backend rules | ||
Zeile 331: | Zeile 366: | ||
# PVUSB trigger for all relevant domains | # PVUSB trigger for all relevant domains | ||
# -------------------------------------- | # -------------------------------------- | ||
[ -n "$ | [ -n "$1" ] || return | ||
# tell PV domain to reload USB | # 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 | grep -v '0000:0000')\" ] || exit 0 ; | ||
rmmod xen_hcd usbcore ; | rmmod xen_hcd usbcore ; | ||
modprobe xen_hcd | modprobe xen_hcd | ||
" | " || true | ||
done | done | ||
} | } | ||
Zeile 347: | Zeile 382: | ||
# tell me what happened | # tell me what happened | ||
# --------------------- | # --------------------- | ||
pvusb_grabbed= | pvusb_grabbed=$(cat /sys/bus/usb/drivers/usbback/grabbed_devices) | ||
for pvusb in $pvusb_grabbed; do | for pvusb in $pvusb_grabbed; do | ||
usb_port=$(echo $pvusb| awk -F: '{print $1}') | 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="$(cat /sys/bus/usb/devices/$usb_port/idVendor)" | ||
dev_id="$dev_id:$(cat /sys/bus/usb/devices/$usb_port/idProduct)" | dev_id="$dev_id:$(cat /sys/bus/usb/devices/$usb_port/idProduct)" | ||
product=$( | product=$(echo "$LSUSB" | grep $dev_id | cut -d\ -f6-) | ||
echo "PVUSB: $usb_port on `xm domname $ | |||
echo "PVUSB: $usb_port on `xm domname $dom_id` ($dom_id) $product" | |||
done | done | ||
} | } | ||
Zeile 366: | Zeile 403: | ||
case $opt in | case $opt in | ||
b) # boot host with static defined rules | b) # boot host with static defined rules | ||
pvusb_boot_init | |||
pvusb_setup_backend | |||
pvusb_trigger $PVUSB_DOMAINS | pvusb_trigger $PVUSB_DOMAINS | ||
;; | ;; | ||
c) # comment e.g. Canon IP4000 | c) # comment e.g. Canon IP4000 | ||
Zeile 384: | Zeile 419: | ||
;; | ;; | ||
q) # don't list PVUSB Ports | q) # don't list PVUSB Ports | ||
QUIET=0 | |||
;; | ;; | ||
r) # list rules | r) # list rules | ||
cat /sys/bus/usb/drivers/usbback/vports | cat /sys/bus/usb/drivers/usbback/vports | ||
;; | ;; | ||
s) # Server Domain name | s) # Server Domain-name or -id | ||
domain=$OPTARG | domain=$OPTARG | ||
if [ "$domain" = "$(echo $domain | tr -d [:alpha:])" ]; then | |||
domain=$(xm domname $domain) | |||
fi | |||
;; | ;; | ||
u) # USB-PORT (3-2) | u) # USB-PORT (3-2) | ||
Zeile 396: | Zeile 434: | ||
;; | ;; | ||
w) # write rule PVUSB | w) # write rule PVUSB | ||
pvusb_init_backend | |||
pvusb_write_rule $domain $usb_port "$comment" | |||
pvusb_setup_backend | |||
#pvusb_trigger $PVUSB_DOMAINS | #pvusb_trigger $PVUSB_DOMAINS | ||
LIST_PVUSB=1 | LIST_PVUSB=1 | ||
Zeile 411: | Zeile 449: | ||
done | done | ||
[ $LIST_PVUSB | [ "$LIST_PVUSB" = "1" ] && pvusb_list | ||
</pre> | </pre> |
Version vom 23. August 2009, 18:10 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.4 $ # Datum: $Date: 2009/08/23 17:06:54 $ # # Author: neobiker # # $Log: pvusb,v $ # 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 $(basename $0) -d device_id -s domain [-c comment] -w $(basename $0) -u usb-port -s domain [-c comment] -w ------------ -b # boot host with static defined PVUSB 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 -q # be quiet -r # list PVUSB rules -w # write/activate PVUSB rule -x # delete PVUSB rule EOT } init () { PVUSB_INIT=0 # only a flag NUM_PORTS=8 # Max 16 ports. CONFIG=/etc/xen/pvusb.conf PVUSB_PID=/var/run/pvusb_loadad.pid [ -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" ] || 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 echo $$ > $PVUSB_PID PVUSB_INIT=1 } pvusb_setup_backend () { # connect USB devices to backend (and restart udevd afterwards) # call once the workaraound to remove Hostcontroller completly # XXX: oterhwise usbbk is already working? if [ $(cat $PVUSB_PID) -le $$ ]; then # 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 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 # get new vusb_port between 2 .. $NUM_PORTS 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 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_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 usb_port=$port break fi done echo "$usb_port" } pvusb_write_connected_devices_static () { # Define where to connect my USB-Devices (static definitions) # ----------------------------------------------------------- # 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? # list 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 # ------------------ [ -e $PVUSB_PID ] && rm $PVUSB_PID pvusb_init_backend # PVUSB write backend rules # ------------------------- pvusb_write_connected_devices_static "$usb_devices" } pvusb_trigger () { # PVUSB trigger for all relevant domains # -------------------------------------- [ -n "$1" ] || return # tell PV domain to reload USB # XXX: better way to trigger domU? for domain in $(echo "$1" | sort -u); do ssh $domain "[ -n \"\$(lsusb | grep -v '0000:0000')\" ] || 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:hlqrs:u:wx:" opt; do case $opt in b) # boot host with static defined rules pvusb_boot_init pvusb_setup_backend pvusb_trigger $PVUSB_DOMAINS ;; 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=$OPTARG if [ "$domain" = "$(echo $domain | tr -d [:alpha:])" ]; then domain=$(xm domname $domain) fi ;; u) # USB-PORT (3-2) usb_port=$OPTARG ;; w) # write rule PVUSB pvusb_init_backend pvusb_write_rule $domain $usb_port "$comment" pvusb_setup_backend #pvusb_trigger $PVUSB_DOMAINS LIST_PVUSB=1 ;; x) # delete PVUSB rule echo "$OPTARG" > /sys/bus/usb/drivers/usbback/remove_vport || true ;; \?) echo "Invalid option: -$OPTARG" >&2 ;; esac done [ "$LIST_PVUSB" = "1" ] && pvusb_list