├── .program ├── etc │ └── systemd │ │ └── system │ │ └── gadgetfs.service ├── home │ └── pi │ │ ├── Desktop │ │ └── USB │ │ └── usbfs │ │ ├── __pycache__ │ │ └── gadget.cpython-35.pyc │ │ ├── gadget │ │ ├── gadget.py │ │ ├── main.py │ │ └── mnt ├── install.sh └── mnt │ └── readme ├── README.md └── ginstall.run /.program/etc/systemd/system/gadgetfs.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=USB Gadget 3 | DefaultDependencies=true 4 | 5 | [Service] 6 | Type=simple 7 | ExecStart=/home/pi/usbfs/gadget 8 | WorkingDirectory=/home/pi/usbfs/ 9 | 10 | [Install] 11 | WantedBy=local-fs.target 12 | -------------------------------------------------------------------------------- /.program/home/pi/Desktop/USB: -------------------------------------------------------------------------------- 1 | [Desktop Entry] 2 | Type=Application 3 | Name=USB Gadget 4 | Exec= python3 /home/pi/usbfs/main.py 5 | StartupNotify=true 6 | Terminal=false -------------------------------------------------------------------------------- /.program/home/pi/usbfs/__pycache__/gadget.cpython-35.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladrobot/Raspberry-GadgetFS/7ab000fbdc5266843b35da3ece85c9137c2d97e9/.program/home/pi/usbfs/__pycache__/gadget.cpython-35.pyc -------------------------------------------------------------------------------- /.program/home/pi/usbfs/gadget: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #dtoverlay dwc2 4 | #modprobe dwc2 5 | modprobe libcomposite 6 | 7 | cd /sys/kernel/config/usb_gadget/ 8 | mkdir -p gadget 9 | cd gadget 10 | echo 0x1d6b > idVendor # Linux Foundation 11 | echo 0x0104 > idProduct # Multifunction Composite Gadget 12 | echo 0x0100 > bcdDevice # v1.0.0 13 | echo 0x0200 > bcdUSB # USB2 14 | echo 0xEF > bDeviceClass 15 | echo 0x02 > bDeviceSubClass 16 | echo 0x01 > bDeviceProtocol 17 | 18 | 19 | mkdir -p strings/0x409 20 | echo "fedcba9876543210" > strings/0x409/serialnumber 21 | echo "by vlad" > strings/0x409/manufacturer 22 | echo "HID & MASS" > strings/0x409/product 23 | mkdir -p configs/c.1/strings/0x409 24 | echo "Config 1:" > configs/c.1/strings/0x409/configuration 25 | echo 250 > configs/c.1/MaxPower 26 | 27 | 28 | 29 | OS descriptors 30 | echo 1 > os_desc/use 31 | echo 0xcd > os_desc/b_vendor_code 32 | echo MSFT100 > os_desc/qw_sign 33 | #echo RNDIS > functions/rndis.usb0/os_desc/interface.rndis/compatible_id 34 | #echo 5162001 > functions/rndis.usb0/os_desc/interface.rndis/sub_compatible_id 35 | 36 | #ln -s configs/c.1 os_desc 37 | #mkdir -p functions/rndis.usb0 38 | #ln -s functions/rndis.usb0 configs/c.1/ 39 | 40 | # Add functions here 41 | #mkdir -p functions/acm.usb0 42 | #ln -s functions/acm.usb0 configs/c.1/ 43 | 44 | 45 | 46 | FILE=/home/pi/usbfs/usbdisk.img 47 | #mkdir -p ${FILE/img/d} 48 | #mount -o loop,ro, -t vfat $FILE ${FILE/img/d} # FOR IMAGE CREATED WITH DD 49 | mkdir -p functions/mass_storage.usb0 50 | echo 1 > functions/mass_storage.usb0/stall 51 | echo 0 > functions/mass_storage.usb0/lun.0/cdrom 52 | echo 0 > functions/mass_storage.usb0/lun.0/ro 53 | echo 0 > functions/mass_storage.usb0/lun.0/nofua 54 | echo $FILE > functions/mass_storage.usb0/lun.0/file 55 | ln -s functions/mass_storage.usb0 configs/c.1/ 56 | 57 | 58 | mkdir -p functions/hid.0 59 | echo 1 > functions/hid.0/protocol #Keyboard 60 | echo 1 > functions/hid.0/subclass #Boot Interface Subclass 61 | echo 8 > functions/hid.0/report_length 62 | echo -ne \\x05\\x01\\x09\\x06\\xA1\\x01\\x05\\x07\\x19\\xE0\\x29` 63 | `\\xE7\\x15\\x00\\x25\\x01\\x75\\x01\\x95\\x08\\x81\\x02` 64 | `\\x95\\x01\\x75\\x08\\x81\\x01\\x95\\x05\\x75\\x01\\x05` 65 | `\\x08\\x19\\x01\\x29\\x05\\x91\\x02\\x95\\x01\\x75\\x03` 66 | `\\x91\\x01\\x95\\x06\\x75\\x08\\x15\\x00\\x25\\x65\\x05` 67 | `\\x07\\x19\\x00\\x29\\x65\\x81\\x00\\xC0 > functions/hid.0/report_desc 68 | ln -s functions/hid.0 configs/c.1/ 69 | 70 | 71 | mkdir -p functions/hid.1 72 | echo 2 > functions/hid.1/protocol #Mouse 73 | echo 1 > functions/hid.1/subclass #Boot Interface Subclass 74 | echo 8 > functions/hid.1/report_length 75 | echo -ne \\x05\\x01\\x09\\x02\\xA1\\x01\\x09\\x01\\xA1\\x00\\x05` 76 | `\\x09\\x19\\x01\\x29\\x03\\x15\\x00\\x25\\x01\\x95\\x03` 77 | `\\x75\\x01\\x81\\x02\\x95\\x01\\x75\\x05\\x81\\x01\\x05` 78 | `\\x01\\x09\\x30\\x09\\x31\\x15\\x81\\x25\\x7F\\x75\\x08` 79 | `\\x95\\x02\\x81\\x06\\xC0\\xC0 > functions/hid.1/report_desc 80 | ln -s functions/hid.1 configs/c.1/ 81 | 82 | 83 | # see gadget configurations below 84 | # End functions 85 | 86 | #udevadm settle -t 5 || : 87 | ls /sys/class/udc > UDC 88 | #ifconfig usb0 10.0.0.2 netmask 255.255.255.252 up 89 | #route add -net default gw 10.0.0.1 90 | sleep 5&&chmod 666 /dev/hidg0 /dev/hidg1 functions/mass_storage.usb0/lun.0/file 91 | -------------------------------------------------------------------------------- /.program/home/pi/usbfs/gadget.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | import subprocess 3 | 4 | 5 | class Application(tk.Frame): 6 | fileMass = '/sys/kernel/config/usb_gadget/gadget/functions/mass_storage.usb0/lun.0/file' 7 | fileIMG ='/home/pi/usbfs/usbdisk.img' 8 | mntDIR = '/home/pi/mnt/' 9 | def hidkey(self, kcode): 10 | h = { 11 | 38: 0x04, 56: 0x05, 54: 0x06, 40: 0x07, 26: 0x08, 12 | 41: 0x09, 42: 0x0A, 43: 0x0B, 31: 0x0C, 44: 0x0D, 13 | 45: 0x0E, 46: 0x0F, 58: 0x10, 57: 0x11, 32: 0x12, 14 | 33: 0x13, 24: 0x14, 27: 0x15, 39: 0x16, 28: 0x17, 15 | 30: 0x18, 55: 0x19, 25: 0x1A, 53: 0x1B, 29: 0x1C, 16 | 52: 0x1D, 10: 0x1E, 11: 0x1F, 12: 0x20, 13: 0x21, 17 | 14: 0x22, 15: 0x23, 16: 0x24, 17: 0x25, 18: 0x26, 18 | 19: 0x27, 36: 0x28, 9: 0x29, 22: 0x2A, 23: 0x2B, 19 | 65: 0x2C, 20: 0x2D, 21: 0x2E, 34: 0x2F, 35: 0x30, 20 | 51: 0x31, 47: 0x33, 48: 0x34, 49: 0x35, 59: 0x36, 21 | 60: 0x37, 61: 0x38, 67: 0x3A, 68: 0x3B, 69: 0x3C, 22 | 70: 0x3D, 71: 0x3E, 72: 0x3F, 73: 0x40, 74: 0x41, 23 | 75: 0x42, 76: 0x43, 95: 0x44, 96: 0x45, 107: 0x46, 24 | 127: 0x48, 118: 0x49, 110: 0x4A, 112: 0x4B, 119: 0x4C, 25 | 115: 0x4D, 117: 0x4E, 113: 0x4F, 114: 0x50, 116: 0x51, 26 | 111: 0x52, 77: 0x53, 106: 0x54, 63: 0x55, 82: 0x56, 27 | 86: 0x57, 104: 0x58, 87: 0x59, 88: 0x5A, 89: 0x5B, 28 | 83: 0x5C, 85: 0x5E, 79: 0x5F, 80: 0x60, 81: 0x61, 29 | 90: 0x62, 91: 0x63, 135: 0x65, 84: 0x97, 37: 0xE0, 30 | 50: 0xE1, 64: 0xE2, 105: 0xE4, 50: 0xE5, 108: 0xE6, 31 | 134: 0xE7 32 | } 33 | return h.get(kcode, 0x00) 34 | 35 | def hidkeymod(self, kcode): 36 | m = { 37 | 37: 0b00000001, #bit 0 is L CTRL 38 | 50: 0b00000010, #bit 1 is L SHIFT 39 | 64: 0b00000100, #bit 2 is L ALT 40 | 204: 0b00000100, #bit 2 is L ALT with L_SHIFT 41 | #00: b'00001000', #bit 3 is L GUI 42 | 105: 0b00010000, #bit 4 is R CTRL 43 | #50: b'00100000', #bit 5 is R SHIFT 44 | 108: 0b01000000, #bit 6 is R ALT 45 | 134: 0b10000000 #bit 7 is R GUI 46 | 47 | } 48 | return m.get(kcode, 0x00) 49 | 50 | def __init__(self, master=None): 51 | super().__init__(master) 52 | self.pack() 53 | self.master.title(u'Keyboard and Mouse') 54 | self.master.geometry('500x400+300+200') # ширина=500, высота=400, x=300, y=200 55 | self.master.resizable(True, True)# размер окна может быть изменён по x и y 56 | self.master.protocol('WM_DELETE_WINDOW', self.window_destroy) 57 | self.keyboard = open("/dev/hidg0","wb",buffering=8) 58 | self.mouse = open("/dev/hidg1","wb",buffering=3) 59 | self.master.bind('', self.keydown) 60 | self.master.bind('', self.keyup) 61 | self.master.bind('', self.move) 62 | self.master.bind('', self.buttondown) 63 | self.master.bind('', self.buttonup) 64 | self.out = bytearray(b'\x00\x00\x00\x00\x00\x00\x00\x00') 65 | self.outmod = 0b00000000 66 | self.outm = bytearray(b'\x00\x00\x00') 67 | self.outmx = 0 68 | self.outmy = 0 69 | self.create_widgets() 70 | 71 | def window_destroy(self): 72 | self.keyboard.close() 73 | self.mouse.close() 74 | self.master.destroy() 75 | 76 | def create_widgets(self): 77 | self.m = tk.Menu(self.master) 78 | self.mc = tk.Menu(self.master, tearoff=0, postcommand=self.showMenu) 79 | self.vMount = tk.IntVar() 80 | self.vM = tk.IntVar() 81 | self.mc.add_radiobutton(label="Mount to PI", command=self.mFS, variable=self.vMount, value=1) 82 | self.mc.add_radiobutton(label="Mount to WIN", command=self.mFS, variable=self.vMount,value=2) 83 | self.vCtrl = tk.IntVar() 84 | self.vAlt = tk.IntVar() 85 | self.vWin = tk.IntVar() 86 | 87 | self.m.add_checkbutton(label="Ctrl", command=self.hKeyD, variable=self.vCtrl) 88 | self.m.add_checkbutton(label="Alt", command=self.hKeyD, variable=self.vAlt) 89 | self.m.add_checkbutton(label="Win", command=self.hKeyD, variable=self.vWin) 90 | 91 | self.m.add_cascade(label="DISK", menu=self.mc) 92 | self.master.config(menu=self.m) 93 | 94 | def hKeyD(self): 95 | self.out[0] = self.hKey() 96 | self.out[2] = 0 97 | self.keyboard.write(self.out) 98 | self.keyboard.flush() 99 | 100 | def keydown(self,event): 101 | self.outmod = self.outmod | self.hidkeymod(event.keycode) 102 | self.out[0] = self.outmod | self.hKey() 103 | if self.hidkeymod(event.keycode) == 0: 104 | self.out[2] = self.hidkey(event.keycode) 105 | else: 106 | self.out[2] = 0 107 | self.keyboard.write(self.out) 108 | self.keyboard.flush() 109 | 110 | def keyup(self,event): 111 | if (self.outmod & 0b00000100) == 4: # L_ALT 112 | if (event.keycode != 64): 113 | self.keydown(event) 114 | elif (self.outmod & 0b01000000) == 64: # R_ALT 115 | if (event.keycode != 108): 116 | self.keydown(event) 117 | if self.outmod & self.hidkeymod(event.keycode): 118 | self.outmod = self.outmod ^ self.hidkeymod(event.keycode) 119 | self.out[0] = self.outmod | self.hKey() 120 | self.out[2] = 0 121 | self.keyboard.write(self.out) 122 | self.keyboard.flush() 123 | 124 | def move(self,event): 125 | xv = event.x - self.outmx 126 | yv = event.y - self.outmy 127 | self.outmx = event.x 128 | self.outmy = event.y 129 | xm = 255 + xv if xv < 0 else xv 130 | ym = 255 + yv if yv < 0 else yv 131 | self.outm[1] = xm if 0 <= xm <= 255 else 0 132 | self.outm[2] = ym if 0 <= ym <= 255 else 0 133 | #print(self.outm) 134 | self.mouse.write(self.outm) 135 | self.mouse.flush() 136 | 137 | def mkey(self, n): 138 | k = { 139 | #2: 0b00000100, #bit 2 is L_Button 140 | 3: 0b00000010, #bit 1 is M_Button 141 | 1: 0b00000001, #bit 0 is R_Button 142 | } 143 | return k.get(n, 0x00) 144 | 145 | def buttondown(self, event): 146 | self.outm[0] = self.outm[0] | self.mkey(event.num) 147 | self.move(event) 148 | 149 | def buttonup(self, event): 150 | self.outm[0] = self.outm[0] ^ self.mkey(event.num) 151 | self.move(event) 152 | 153 | def showMenu(self): 154 | p = open(self.fileMass) 155 | result = p.read() 156 | p.close() 157 | if result =='': 158 | self.vMount.set(1) 159 | self.vM.set(1) 160 | else: 161 | self.vMount.set(2) 162 | self.vM.set(2) 163 | 164 | def mFS(self): 165 | if self.vMount.get() != self.vM.get(): 166 | if self.vMount.get() == 1: 167 | result = subprocess.run(['echo > '+self.fileMass], shell=True) 168 | result = subprocess.run(['sudo','mount','-o','loop,rw,uid=1000,gid=1000','-t','vfat', self.fileIMG, self.mntDIR]) 169 | #, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 170 | #print(result.stdout) 171 | elif self.vMount.get() == 2: 172 | result = subprocess.run(['sudo', 'umount', '-f', self.mntDIR]) 173 | result = subprocess.run(['echo '+self.fileIMG+' > '+self.fileMass], shell=True) 174 | 175 | def hKey(self): 176 | outHOT = 0b00000000 177 | outHOT = outHOT | 0b00000001 if self.vCtrl.get() == 1 else outHOT 178 | outHOT = outHOT | 0b00000100 if self.vAlt.get() == 1 else outHOT 179 | outHOT = outHOT | 0b00001000 if self.vWin.get() == 1 else outHOT 180 | return(outHOT) 181 | 182 | if __name__ == '__main__': 183 | root = tk.Tk() 184 | app = Application(master=root) 185 | app.mainloop() -------------------------------------------------------------------------------- /.program/home/pi/usbfs/main.py: -------------------------------------------------------------------------------- 1 | import tkinter as tk 2 | from gadget import Application 3 | 4 | root = tk.Tk() 5 | app = Application(master=root) 6 | app.mainloop() -------------------------------------------------------------------------------- /.program/home/pi/usbfs/mnt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | file = /sys/kernel/config/usb_gadget/gadget/configs/c.1/mass_storage.usb0 3 | 4 | if [ "$1" = "host" ]; then 5 | rm $file 6 | fi 7 | -------------------------------------------------------------------------------- /.program/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | file=/boot/config.txt 3 | 4 | cp -R home/ / 5 | cp -R etc/ / 6 | 7 | st=(`cat $file |grep -e '^dtoverlay=dwc2'`) 8 | if [ ${#st[@]} = 0 ] 9 | then 10 | echo 'dtoverlay=dwc2' >> $file 11 | fi 12 | 13 | mkdir /home/pi/mnt 14 | chown -R pi:pi /home/pi/mnt/ /home/pi/usbfs/ /home/pi/Desktop/ 15 | systemctl enable gadgetfs.service 16 | #rm -r .program/ 17 | 18 | echo 'Install....OK' 19 | echo 'Reboot system' 20 | -------------------------------------------------------------------------------- /.program/mnt/readme: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Raspberry-GadgetFS 2 | Raspberry PI Zero USB gadget. Mouse, Keyboard, USB flash drive. 3 | 4 | ginstall.run - installer 5 | 6 | dir .program - code 7 | 8 | example create USB flash dd if=/dev/zero of=/home/pi/usbfs/usbdisk.img bs=1024 count=1024 9 | -------------------------------------------------------------------------------- /ginstall.run: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vladrobot/Raspberry-GadgetFS/7ab000fbdc5266843b35da3ece85c9137c2d97e9/ginstall.run --------------------------------------------------------------------------------