diff --git a/kvmapp/system/init.d/S03usbdev b/kvmapp/system/init.d/S03usbdev index c650e6b..ab12274 100755 --- a/kvmapp/system/init.d/S03usbdev +++ b/kvmapp/system/init.d/S03usbdev @@ -82,6 +82,7 @@ start_usb_dev(){ ln -s functions/hid.GS2 configs/c.1 fi + # dedicated for media if [ -e /boot/usb.disk0 ] then mkdir functions/mass_storage.disk0 @@ -95,17 +96,20 @@ start_usb_dev(){ disk=$(cat /boot/usb.disk0) if [ -z "${disk}" ] then - # if [ ! -e /mnt/usbdisk.img ] - # then - # fallocate -l 8G /mnt/usbdisk.img - # mkfs.vfat /mnt/usbdisk.img - # fi - echo /dev/mmcblk0p3 > functions/mass_storage.disk0/lun.0/file + echo "" > functions/mass_storage.disk0/lun.0/file else cat /boot/usb.disk0 > functions/mass_storage.disk0/lun.0/file fi fi + # mount data partition + if [ -e /boot/usb.disk1 ] + then + mkdir functions/mass_storage.disk1 + ln -s functions/mass_storage.disk1 configs/c.1/ + echo /dev/mmcblk0p3 > functions/mass_storage.disk1/lun.0/file + fi + ls /sys/class/udc/ | cat > UDC echo device > /proc/cviusb/otg_role } diff --git a/server/proto/vm.go b/server/proto/vm.go index 21d3844..3c56533 100644 --- a/server/proto/vm.go +++ b/server/proto/vm.go @@ -57,6 +57,7 @@ type DeleteScriptReq struct { type GetVirtualDeviceRsp struct { Network bool `json:"network"` + Media bool `json:"media"` Disk bool `json:"disk"` } diff --git a/server/service/storage/image.go b/server/service/storage/image.go index 63360ed..5f8118d 100644 --- a/server/service/storage/image.go +++ b/server/service/storage/image.go @@ -16,7 +16,7 @@ import ( const ( imageDirectory = "/data" - imageNone = "/dev/mmcblk0p3" + imageNone = "" cdromFlag = "/sys/kernel/config/usb_gadget/g0/functions/mass_storage.disk0/lun.0/cdrom" mountDevice = "/sys/kernel/config/usb_gadget/g0/functions/mass_storage.disk0/lun.0/file" roFlag = "/sys/kernel/config/usb_gadget/g0/functions/mass_storage.disk0/lun.0/ro" @@ -105,8 +105,9 @@ func (s *Service) MountImage(c *gin.Context) { // reset usb commands := []string{ - "echo > /sys/kernel/config/usb_gadget/g0/UDC", - "ls /sys/class/udc/ | cat > /sys/kernel/config/usb_gadget/g0/UDC", + // this should not be required for media change, reset of the full gadget can break hid on some devices + //"echo > /sys/kernel/config/usb_gadget/g0/UDC", + //"ls /sys/class/udc/ | cat > /sys/kernel/config/usb_gadget/g0/UDC", } for _, command := range commands { diff --git a/server/service/vm/virtual-device.go b/server/service/vm/virtual-device.go index 2eb40e9..3804526 100644 --- a/server/service/vm/virtual-device.go +++ b/server/service/vm/virtual-device.go @@ -14,7 +14,8 @@ import ( const ( virtualNetwork = "/boot/usb.rndis0" - virtualDisk = "/boot/usb.disk0" + virtualMedia = "/boot/usb.disk0" + virtualDisk = "/boot/usb.disk1" ) var ( @@ -31,16 +32,29 @@ var ( "/etc/init.d/S03usbdev start", } - mountDiskCommands = []string{ + mountMediaCommands = []string{ "touch /boot/usb.disk0", "/etc/init.d/S03usbdev stop", "/etc/init.d/S03usbdev start", } + unmountMediaCommands = []string{ + "/etc/init.d/S03usbdev stop", + "rm -rf /sys/kernel/config/usb_gadget/g0/configs/c.1/mass_storage.disk0", + "rm /boot/usb.disk0", + "/etc/init.d/S03usbdev start", + } + + mountDiskCommands = []string{ + "touch /boot/usb.disk1", + "/etc/init.d/S03usbdev stop", + "/etc/init.d/S03usbdev start", + } + unmountDiskCommands = []string{ "/etc/init.d/S03usbdev stop", - "rm -rf /sys/kernel/config/usb_gadget/g0/configs/c.1/mass_storage.disk0", - "rm /boot/usb.disk0", + "rm -rf /sys/kernel/config/usb_gadget/g0/configs/c.1/mass_storage.disk1", + "rm /boot/usb.disk1", "/etc/init.d/S03usbdev start", } ) @@ -49,10 +63,12 @@ func (s *Service) GetVirtualDevice(c *gin.Context) { var rsp proto.Response network, _ := isDeviceExist(virtualNetwork) + media, _ := isDeviceExist(virtualMedia) disk, _ := isDeviceExist(virtualDisk) rsp.OkRspWithData(c, &proto.GetVirtualDeviceRsp{ Network: network, + Media: media, Disk: disk, }) log.Debugf("get virtual device success") @@ -80,6 +96,15 @@ func (s *Service) UpdateVirtualDevice(c *gin.Context) { } else { commands = unmountNetworkCommands } + case "media": + device = virtualMedia + + exist, _ := isDeviceExist(device) + if !exist { + commands = mountMediaCommands + } else { + commands = unmountMediaCommands + } case "disk": device = virtualDisk diff --git a/web/src/i18n/locales/en.ts b/web/src/i18n/locales/en.ts index 534d4f0..58e24c8 100644 --- a/web/src/i18n/locales/en.ts +++ b/web/src/i18n/locales/en.ts @@ -266,7 +266,9 @@ const en = { }, hidOnly: 'HID-Only Mode', disk: 'Virtual Disk', - diskDesc: 'Mount virtual U-disk on the remote host', + diskDesc: 'Mount SD card on the remote host', + media: "Virtual Image", + mediaDesc: 'Attach virtual image device to the remote host', network: 'Virtual Network', networkDesc: 'Mount virtual network card on the remote host', reboot: 'Reboot', diff --git a/web/src/pages/desktop/menu/settings/device/virtual-devices.tsx b/web/src/pages/desktop/menu/settings/device/virtual-devices.tsx index e378223..ffe2ad0 100644 --- a/web/src/pages/desktop/menu/settings/device/virtual-devices.tsx +++ b/web/src/pages/desktop/menu/settings/device/virtual-devices.tsx @@ -8,8 +8,9 @@ export const VirtualDevices = () => { const { t } = useTranslation(); const [isNetworkOn, setIsNetworkOn] = useState(false); + const [isMediaOn, setIsMediaOn] = useState(false); const [isDiskOn, setIsDiskOn] = useState(false); - const [loading, setLoading] = useState(''); // '' | 'network' | 'disk' + const [loading, setLoading] = useState(''); // '' | 'network' | 'media' | 'disk' useEffect(() => { api.getVirtualDevice().then((rsp) => { @@ -18,11 +19,12 @@ export const VirtualDevices = () => { } setIsNetworkOn(rsp.data.network); + setIsMediaOn(rsp.data.media); setIsDiskOn(rsp.data.disk); }); }, []); - function update(device: 'network' | 'disk') { + function update(device: 'network' | 'media' | 'disk') { if (loading) return; setLoading(device); @@ -33,10 +35,16 @@ export const VirtualDevices = () => { return; } - if (device === 'network') { - setIsNetworkOn(rsp.data.on); - } else { - setIsDiskOn(rsp.data.on); + switch (device) { + case 'network': + setIsNetworkOn(rsp.data.on); + break; + case 'media': + setIsMediaOn(rsp.data.on); + break; + case 'disk': + setIsDiskOn(rsp.data.on); + break; } }) .finally(() => { @@ -46,6 +54,15 @@ export const VirtualDevices = () => { return ( <> +
+
+ {t('settings.device.media')} + {t('settings.device.mediaDesc')} +
+ + update('media')} /> +
+
{t('settings.device.disk')}