[USB]
authorCameron Gutman <aicommander@gmail.com>
Sun, 12 Feb 2012 04:59:51 +0000 (04:59 +0000)
committerCameron Gutman <aicommander@gmail.com>
Sun, 12 Feb 2012 04:59:51 +0000 (04:59 +0000)
- We proudly merge the first charge of the usb-bringup branch. We do want to stress hardware support is still under heavy development and testing in real hardware is experimental
- Merge the Human Interface Device Stack(HID) which is used for mice / keyboards and other devices which use the USB interface, consisting of hidusb, hidparse, hidclass, mouhid, kbdhid
- Merge the composite driver, supports USB composite devices, laid out in usbccgp
- Merge the generic hub driver, which supports the USB root hub and in future USB hubs. Driver is usbhub
- Merge the Open Host Controller Interface driver (ohci)
- Merge the Enhanced Host Controller Interface driver (ehci)
- Merge the many fixes in other areas of ReactOS needed for USB to work (ntoskrnl, pci, inf, umpnpmgr, usetup)
- Special thanks goes the Haiku team, whose excellent code has provided a great base for the development of the new ReactOS USB / HID stack
- The development of the USB stack has shown the great potential when ReactOS developers team up together to achieve a common goal. The involved developers are here, listed alphabetically:

Alex Ionescu
Amine Khaldi
Cameron Gutman
Johannes Anderwald
Michel Martin
Thomas Faber
Thomas Lotz(Haiku)

Let's start the ReactOS revolution

svn path=/trunk/; revision=55555

192 files changed:
1  2  3 
reactos/base/services/umpnpmgr/umpnpmgr.c
reactos/base/setup/usetup/interface/devinst.c
reactos/base/setup/usetup/interface/usetup.c
reactos/base/setup/usetup/partlist.c
reactos/boot/bootdata/hivesys_amd64.inf
reactos/boot/bootdata/hivesys_i386.inf
reactos/boot/bootdata/packages/reactos.dff
reactos/boot/bootdata/txtsetup.sif
reactos/dll/win32/hid/hid.c
reactos/dll/win32/hid/stubs.c
reactos/drivers/CMakeLists.txt
reactos/drivers/bus/acpi/buspdo.c
reactos/drivers/bus/pci/fdo.c
reactos/drivers/bus/pci/pci.h
reactos/drivers/bus/pci/pdo.c
reactos/drivers/bus/pcix/enum.c
reactos/drivers/bus/pcix/fdo.c
reactos/drivers/bus/pcix/pdo.c
reactos/drivers/drivers.rbuild
reactos/drivers/filters/CMakeLists.txt
reactos/drivers/filters/directory.rbuild
reactos/drivers/filters/mountmgr/CMakeLists.txt
reactos/drivers/filters/mountmgr/database.c
reactos/drivers/filters/mountmgr/device.c
reactos/drivers/filters/mountmgr/mntmgr.h
reactos/drivers/filters/mountmgr/mountmgr.c
reactos/drivers/filters/mountmgr/mountmgr.rbuild
reactos/drivers/filters/mountmgr/mountmgr.rc
reactos/drivers/filters/mountmgr/notify.c
reactos/drivers/filters/mountmgr/point.c
reactos/drivers/filters/mountmgr/symlink.c
reactos/drivers/filters/mountmgr/uniqueid.c
reactos/drivers/hid/CMakeLists.txt
reactos/drivers/hid/directory.rbuild
reactos/drivers/hid/hidclass/CMakeLists.txt
reactos/drivers/hid/hidclass/fdo.c
reactos/drivers/hid/hidclass/hidclass.c
reactos/drivers/hid/hidclass/hidclass.rbuild
reactos/drivers/hid/hidclass/hidclass.rc
reactos/drivers/hid/hidclass/hidclass.spec
reactos/drivers/hid/hidclass/pdo.c
reactos/drivers/hid/hidclass/precomp.h
reactos/drivers/hid/hidparse/CMakeLists.txt
reactos/drivers/hid/hidparse/hidparse.c
reactos/drivers/hid/hidparse/hidparse.h
reactos/drivers/hid/hidparse/hidparse.rbuild
reactos/drivers/hid/hidparse/hidparse.rc
reactos/drivers/hid/hidparse/hidparse.spec
reactos/drivers/hid/hidusb/CMakeLists.txt
reactos/drivers/hid/hidusb/hidusb.c
reactos/drivers/hid/hidusb/hidusb.h
reactos/drivers/hid/hidusb/hidusb.rbuild
reactos/drivers/hid/hidusb/hidusb.rc
reactos/drivers/hid/kbdhid/CMakeLists.txt
reactos/drivers/hid/kbdhid/kbdhid.c
reactos/drivers/hid/kbdhid/kbdhid.h
reactos/drivers/hid/kbdhid/kbdhid.rbuild
reactos/drivers/hid/kbdhid/kbdhid.rc
reactos/drivers/hid/mouhid/CMakeLists.txt
reactos/drivers/hid/mouhid/mouhid.c
reactos/drivers/hid/mouhid/mouhid.h
reactos/drivers/hid/mouhid/mouhid.rbuild
reactos/drivers/hid/mouhid/mouhid.rc
reactos/drivers/input/kbdclass/kbdclass.c
reactos/drivers/input/kbdclass/kbdclass.h
reactos/drivers/input/mouclass/mouclass.c
reactos/drivers/input/mouclass/mouclass.h
reactos/drivers/storage/class/CMakeLists.txt
reactos/drivers/storage/class/class2/class2.c
reactos/drivers/storage/class/disk_new/CMakeLists.txt
reactos/drivers/storage/class/disk_new/data.c
reactos/drivers/storage/class/disk_new/disk.c
reactos/drivers/storage/class/disk_new/disk.h
reactos/drivers/storage/class/disk_new/disk.rc
reactos/drivers/storage/class/disk_new/diskdev.inf
reactos/drivers/storage/class/disk_new/diskwmi.c
reactos/drivers/storage/class/disk_new/enum.c
reactos/drivers/storage/class/disk_new/geometry.c
reactos/drivers/storage/class/disk_new/part.c
reactos/drivers/storage/class/disk_new/pnp.c
reactos/drivers/storage/classpnp/CMakeLists.txt
reactos/drivers/storage/classpnp/classpnp.rbuild
reactos/drivers/storage/classpnp/classpnp.spec
reactos/drivers/usb/CMakeLists.txt
reactos/drivers/usb/directory.rbuild
reactos/drivers/usb/usbccgp/CMakeLists.txt
reactos/drivers/usb/usbccgp/descriptor.c
reactos/drivers/usb/usbccgp/fdo.c
reactos/drivers/usb/usbccgp/function.c
reactos/drivers/usb/usbccgp/misc.c
reactos/drivers/usb/usbccgp/pdo.c
reactos/drivers/usb/usbccgp/usbccgp.c
reactos/drivers/usb/usbccgp/usbccgp.h
reactos/drivers/usb/usbccgp/usbccgp.rbuild
reactos/drivers/usb/usbccgp/usbccgp.rc
reactos/drivers/usb/usbd/CMakeLists.txt
reactos/drivers/usb/usbd/usbd.c
reactos/drivers/usb/usbd/usbd.rbuild
reactos/drivers/usb/usbd/usbd.spec
reactos/drivers/usb/usbehci/CMakeLists.txt
reactos/drivers/usb/usbehci/hardware.cpp
reactos/drivers/usb/usbehci/hardware.h
reactos/drivers/usb/usbehci/hcd_controller.cpp
reactos/drivers/usb/usbehci/hub_controller.cpp
reactos/drivers/usb/usbehci/interfaces.h
reactos/drivers/usb/usbehci/memory_manager.cpp
reactos/drivers/usb/usbehci/misc.cpp
reactos/drivers/usb/usbehci/purecall.cpp
reactos/drivers/usb/usbehci/usb_device.cpp
reactos/drivers/usb/usbehci/usb_queue.cpp
reactos/drivers/usb/usbehci/usb_request.cpp
reactos/drivers/usb/usbehci/usbehci.cpp
reactos/drivers/usb/usbehci/usbehci.h
reactos/drivers/usb/usbehci/usbehci.rbuild
reactos/drivers/usb/usbehci/usbehci.rc
reactos/drivers/usb/usbhub/CMakeLists.txt
reactos/drivers/usb/usbhub/fdo.c
reactos/drivers/usb/usbhub/misc.c
reactos/drivers/usb/usbhub/pdo.c
reactos/drivers/usb/usbhub/usbhub.c
reactos/drivers/usb/usbhub/usbhub.h
reactos/drivers/usb/usbhub/usbhub.rbuild
reactos/drivers/usb/usbhub/usbhub.rc
reactos/drivers/usb/usbohci/CMakeLists.txt
reactos/drivers/usb/usbohci/hardware.cpp
reactos/drivers/usb/usbohci/hardware.h
reactos/drivers/usb/usbohci/hcd_controller.cpp
reactos/drivers/usb/usbohci/hub_controller.cpp
reactos/drivers/usb/usbohci/interfaces.h
reactos/drivers/usb/usbohci/memory_manager.cpp
reactos/drivers/usb/usbohci/misc.cpp
reactos/drivers/usb/usbohci/purecall.cpp
reactos/drivers/usb/usbohci/usb_device.cpp
reactos/drivers/usb/usbohci/usb_queue.cpp
reactos/drivers/usb/usbohci/usb_request.cpp
reactos/drivers/usb/usbohci/usbohci.cpp
reactos/drivers/usb/usbohci/usbohci.h
reactos/drivers/usb/usbohci/usbohci.rbuild
reactos/drivers/usb/usbohci/usbohci.rc
reactos/drivers/usb/usbstor/CMakeLists.txt
reactos/drivers/usb/usbstor/descriptor.c
reactos/drivers/usb/usbstor/disk.c
reactos/drivers/usb/usbstor/error.c
reactos/drivers/usb/usbstor/fdo.c
reactos/drivers/usb/usbstor/misc.c
reactos/drivers/usb/usbstor/pdo.c
reactos/drivers/usb/usbstor/queue.c
reactos/drivers/usb/usbstor/scsi.c
reactos/drivers/usb/usbstor/usbstor.c
reactos/drivers/usb/usbstor/usbstor.h
reactos/drivers/usb/usbstor/usbstor.rbuild
reactos/hal/halx86/acpi/halpnpdd.c
reactos/hal/halx86/legacy/bussupp.c
reactos/hal/halx86/legacy/halpnpdd.c
reactos/include/ddk/hidclass.h
reactos/include/ddk/hidpddi.h
reactos/include/ddk/hidport.h
reactos/include/ddk/ntddk.h
reactos/include/psdk/hidusage.h
reactos/include/psdk/usb.h
reactos/lib/drivers/CMakeLists.txt
reactos/lib/drivers/directory.rbuild
reactos/lib/drivers/hidparser/CMakeLists.txt
reactos/lib/drivers/hidparser/api.c
reactos/lib/drivers/hidparser/context.c
reactos/lib/drivers/hidparser/hidparser.c
reactos/lib/drivers/hidparser/hidparser.h
reactos/lib/drivers/hidparser/hidparser.rbuild
reactos/lib/drivers/hidparser/parser.c
reactos/lib/drivers/hidparser/parser.h
reactos/lib/sdk/wdmguid/wdmguid.c
reactos/media/inf/CMakeLists.txt
reactos/media/inf/cdrom.inf
reactos/media/inf/input.inf
reactos/media/inf/keyboard.inf
reactos/media/inf/msmouse.inf
reactos/media/inf/syssetup.inf
reactos/media/inf/syssetup.inf.tpl
reactos/media/inf/usb.inf
reactos/media/inf/usbport.inf
reactos/media/inf/usbstor.inf
reactos/ntoskrnl/include/internal/io.h
reactos/ntoskrnl/include/ntoskrnl.h
reactos/ntoskrnl/io/iomgr/device.c
reactos/ntoskrnl/io/iomgr/deviface.c
reactos/ntoskrnl/io/iomgr/driver.c
reactos/ntoskrnl/io/iomgr/iorsrce.c
reactos/ntoskrnl/io/iomgr/volume.c
reactos/ntoskrnl/io/pnpmgr/plugplay.c
reactos/ntoskrnl/io/pnpmgr/pnpmgr.c
reactos/ntoskrnl/io/pnpmgr/pnpres.c
reactos/ntoskrnl/ob/obname.c

Simple merge
index 912a1c7,0000000,512ead1..512ead1
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,893 -1,0 -1,890 +1,890 @@@@
-  ;drivers\usb\miniport\usbohci\usbohci.sys           2
-  ;drivers\usb\miniport\usbuhci\usbuhci.sys           2
-  ;drivers\usb\usbhub\usbhub.sys                      2
-  ;drivers\usb\usbport\usbport.sys                    2
-  ;drivers\usb\nt4compat\usbdriver\usbdriver.sys      2
 + ; Main ReactOS package
 + 
 + .Set DiskLabelTemplate="ReactOS"                ; Label of disk
 + .Set CabinetNameTemplate="reactos.cab"          ; reactos.cab
 + .Set InfFileName="reactos.inf"                  ; reactos.inf
 + 
 + 
 + ;.Set Cabinet=on
 + ;.Set Compress=on
 + 
 + .InfBegin
 + [Version]
 + Signature = "$ReactOS$"
 + 
 + [Directories]
 + 1 = system32
 + 2 = system32\drivers
 + 3 = Fonts
 + 4 =
 + 5 = system32\drivers\etc
 + 6 = inf
 + 7 = bin
 + 8 = media
 + 
 + .InfEnd
 + 
 + ; Contents of disk
 + .InfBegin
 + [SourceFiles]
 + .InfEnd
 + 
 + 
 + ; Base files
 + base\applications\cacls\cacls.exe                       1
 + base\applications\calc\calc.exe                         1
 + base\applications\charmap\charmap.exe                   1
 + base\applications\cmdutils\dbgprint\dbgprint.exe        1
 + base\applications\cmdutils\doskey\doskey.exe            1
 + base\applications\cmdutils\find\find.exe                1
 + base\applications\cmdutils\hostname\hostname.exe        1
 + base\applications\cmdutils\lodctr\lodctr.exe            1
 + base\applications\cmdutils\more\more.exe                1
 + base\applications\cmdutils\reg\reg.exe                  1
 + base\applications\cmdutils\xcopy\xcopy.exe              1
 + base\applications\control\control.exe                   1
 + base\applications\dxdiag\dxdiag.exe                     1
 + base\applications\extrac32\extrac32.exe                 1
 + base\applications\findstr\findstr.exe                   1
 + base\applications\fontview\fontview.exe                 1
 + base\applications\iexplore\iexplore.exe                 1
 + base\applications\games\solitaire\sol.exe               1
 + base\applications\games\spider\spider.exe               1
 + base\applications\games\winmine\winmine.exe             1
 + base\applications\hh\hh.exe                             4
 + base\applications\kbswitch\kbswitch.exe                 1
 + base\applications\kbswitch\kbsdll\kbsdll.dll            1
 + base\applications\logoff\logoff.exe                     1
 + base\applications\magnify\magnify.exe                   1
 + base\applications\mplay32\mplay32.exe                   1
 + base\applications\msconfig\msconfig.exe                 1
 + base\applications\mscutils\devmgmt\devmgmt.exe          1
 + base\applications\mscutils\eventvwr\eventvwr.exe        1
 + base\applications\mscutils\servman\servman.exe          1
 + base\applications\mspaint\mspaint.exe                   1
 + base\applications\mstsc\mstsc.exe                       1
 + base\applications\network\arp\arp.exe                   1
 + base\applications\network\dwnl\dwnl.exe                 1
 + base\applications\network\finger\finger.exe             1
 + base\applications\network\ftp\ftp.exe                   1
 + base\applications\network\ipconfig\ipconfig.exe         1
 + base\applications\network\net\net.exe                   1
 + base\applications\network\netstat\netstat.exe           1
 + base\applications\network\nslookup\nslookup.exe         1
 + base\applications\network\ping\ping.exe                 1
 + base\applications\network\route\route.exe               1
 + base\applications\network\telnet\telnet.exe             1
 + base\applications\network\tracert\tracert.exe           1
 + base\applications\network\whois\whois.exe               1
 + base\applications\network\wlanconf\wlanconf.exe         1
 + base\applications\notepad\notepad.exe                   1
 + base\applications\rapps\rapps.exe                       1
 + base\applications\regedit\regedit.exe                   4
 + base\applications\regedit\clb\clb.dll                   1
 + base\applications\regedt32\regedt32.exe                 1
 + base\applications\sc\sc.exe                             1
 + base\applications\screensavers\3dtext\3dtext.scr        1
 + base\applications\screensavers\logon\logon.scr          1
 + base\applications\shutdown\shutdown.exe                 1
 + base\applications\sndrec32\sndrec32.exe                 1
 + base\applications\sndvol32\sndvol32.exe                 1
 + base\applications\taskmgr\taskmgr.exe                   1
 + base\applications\winhlp32\winhlp32.exe                 4
 + base\applications\winver\winver.exe                     1
 + base\applications\wordpad\wordpad.exe                   1
 + base\applications\write\write.exe                       1
 + 
 + base\services\audiosrv\audiosrv.exe                 1
 + base\services\eventlog\eventlog.exe                 1
 + base\services\rpcss\rpcss.exe                       1
 + base\services\spoolsv\spoolsv.exe                   1
 + base\services\svchost\svchost.exe                   1
 + base\services\tcpsvcs\tcpsvcs.exe                   1
 + base\services\tcpsvcs\quotes                        5
 + base\services\telnetd\telnetd.exe                   1
 + base\services\thmsvc\thmsvc.exe                     1
 + base\services\umpnpmgr\umpnpmgr.exe                 1
 + base\services\wlansvc\wlansvc.exe                   1
 + 
 + base\setup\setup\setup.exe                          1
 + base\setup\vmwinst\vmwinst.exe                      1
 + 
 + base\shell\cmd\cmd.exe                              1
 + base\shell\explorer\explorer.exe                    4   optional
 + base\shell\explorer\explorer-cfg-template.xml       4   optional
 + base\shell\explorer\notifyhook\notifyhook.dll       1   optional
 + base\shell\explorer-new\explorer_new.exe            4   optional
 + 
 + base\system\autochk\autochk.exe                     1
 + base\system\bootok\bootok.exe                       1
 + base\system\diskpart\diskpart.exe                   1
 + base\system\expand\expand.exe                       1
 + base\system\subst\subst.exe                         1
 + base\system\format\format.exe                       1
 + base\system\lsass\lsass.exe                         1
 + base\system\msiexec\msiexec.exe                     1
 + base\system\regsvr32\regsvr32.exe                   1
 + base\system\rundll32\rundll32.exe                   1
 + base\system\runonce\runonce.exe                     1
 + base\system\services\services.exe                   1
 + base\system\smss\smss.exe                           1
 + base\system\smss2\smss2.exe                         1
 + base\system\userinit\userinit.exe                   1
 + base\system\winlogon\winlogon.exe                   1
 + 
 + ; Dynamic Link Libraries
 + dll\3rdparty\dxtn\dxtn.dll                          1   optional
 + dll\3rdparty\libjpeg\libjpeg.dll                    1
 + dll\3rdparty\libpng\libpng.dll                      1
 + dll\3rdparty\libtiff\libtiff.dll                    1
 + dll\3rdparty\libxslt\libxslt.dll                    1
 + dll\3rdparty\mesa32\mesa32.dll                      1
 + 
 + dll\cpl\access\access.cpl                           1
 + dll\cpl\appwiz\appwiz.cpl                           1
 + dll\cpl\console\console.dll                         1
 + dll\cpl\desk\desk.cpl                               1
 + dll\cpl\hdwwiz\hdwwiz.cpl                           1
 + dll\cpl\input\input.dll                             1
 + dll\cpl\inetcpl\inetcpl.cpl                         1
 + dll\cpl\intl\intl.cpl                               1
 + dll\cpl\joy\joy.cpl                                 1
 + ;dll\cpl\liccpa\liccpa.cpl                          1
 + dll\cpl\main\main.cpl                               1
 + dll\cpl\mmsys\mmsys.cpl                             1
 + dll\cpl\ncpa\ncpa.cpl                               1
 + ;dll\cpl\odbccp32\odbccp32.cpl                      1
 + dll\cpl\powercfg\powercfg.cpl                       1
 + dll\cpl\sysdm\sysdm.cpl                             1
 + ;dll\cpl\telephon\telephon.cpl                      1
 + dll\cpl\timedate\timedate.cpl                       1
 + ;dll\cpl\usrmgr\usrmgr.cpl                          1
 + 
 + dll\directx\amstream\amstream.dll                   1
 + ;dll\directx\bdaplgin\bdaplgin.ax                    1
 + dll\directx\d3d8thk\d3d8thk.dll                     1
 + dll\directx\devenum\devenum.dll                     1
 + dll\directx\dinput\dinput.dll                       1
 + dll\directx\dinput8\dinput8.dll                     1
 + dll\directx\dmusic\dmusic.dll                       1
 + dll\directx\dplay\dplay.dll                         1
 + dll\directx\dplayx\dplayx.dll                       1
 + dll\directx\dsound\dsound.dll                       1
 + dll\directx\dxdiagn\dxdiagn.dll                     1
 + dll\directx\ksproxy\ksproxy.ax                      1
 + dll\directx\ksuser\ksuser.dll                       1
 + dll\directx\msdmo\msdmo.dll                         1
 + ;dll\directx\msdvbnp\msdvbnp.ax                      1
 + ;dll\directx\msvidctl\msvidctl.dll                   1
 + dll\directx\qedit\qedit.dll                         1
 + dll\directx\quartz\quartz.dll                       1
 + dll\directx\wine\ddraw\ddraw.dll                    1
 + dll\directx\wine\d3d8\d3d8.dll                      1
 + dll\directx\wine\d3d9\d3d9.dll                      1
 + dll\directx\wine\wined3d\wined3d.dll                1
 + 
 + dll\keyboard\kbda1\kbda1.dll                        1
 + dll\keyboard\kbda2\kbda2.dll                        1
 + dll\keyboard\kbda3\kbda3.dll                        1
 + dll\keyboard\kbdal\kbdal.dll                        1
 + dll\keyboard\kbdarme\kbdarme.dll                    1
 + dll\keyboard\kbdarmw\kbdarmw.dll                    1
 + dll\keyboard\kbdaze\kbdaze.dll                      1
 + dll\keyboard\kbdazel\kbdazel.dll                    1
 + dll\keyboard\kbdbe\kbdbe.dll                        1
 + dll\keyboard\kbdbga\kbdbga.dll                      1
 + dll\keyboard\kbdbgm\kbdbgm.dll                      1
 + dll\keyboard\kbdbgt\kbdbgt.dll                      1
 + dll\keyboard\kbdblr\kbdblr.dll                      1
 + dll\keyboard\kbdbr\kbdbr.dll                        1
 + dll\keyboard\kbdbur\kbdbur.dll                      1
 + dll\keyboard\kbdcan\kbdcan.dll                      1
 + dll\keyboard\kbdcr\kbdcr.dll                        1
 + dll\keyboard\kbdcz\kbdcz.dll                        1
 + dll\keyboard\kbdcz1\kbdcz1.dll                      1
 + dll\keyboard\kbdda\kbdda.dll                        1
 + dll\keyboard\kbddv\kbddv.dll                        1
 + dll\keyboard\kbdes\kbdes.dll                        1
 + dll\keyboard\kbdest\kbdest.dll                      1
 + dll\keyboard\kbdfc\kbdfc.dll                        1
 + dll\keyboard\kbdfi\kbdfi.dll                        1
 + dll\keyboard\kbdfr\kbdfr.dll                        1
 + dll\keyboard\kbdgeo\kbdgeo.dll                      1
 + dll\keyboard\kbdgerg\kbdgerg.dll                    1
 + dll\keyboard\kbdgneo\kbdgneo.dll                    1
 + dll\keyboard\kbdgr\kbdgr.dll                        1
 + dll\keyboard\kbdgrist\kbdgrist.dll                  1
 + dll\keyboard\kbdhe\kbdhe.dll                        1
 + dll\keyboard\kbdheb\kbdheb.dll                      1
 + dll\keyboard\kbdhu\kbdhu.dll                        1
 + dll\keyboard\kbdic\kbdic.dll                        1
 + dll\keyboard\kbdinasa\kbdinasa.dll                  1
 + dll\keyboard\kbdinben\kbdinben.dll                  1
 + dll\keyboard\kbdindev\kbdindev.dll                  1
 + dll\keyboard\kbdinguj\kbdinguj.dll                  1
 + dll\keyboard\kbdinmal\kbdinmal.dll                  1
 + dll\keyboard\kbdir\kbdir.dll                        1
 + dll\keyboard\kbdit\kbdit.dll                        1
 + dll\keyboard\kbdja\kbdja.dll                        1
 + dll\keyboard\kbdkaz\kbdkaz.dll                      1
 + dll\keyboard\kbdko\kbdko.dll                        1
 + dll\keyboard\kbdla\kbdla.dll                        1
 + dll\keyboard\kbdlt1\kbdlt1.dll                      1
 + dll\keyboard\kbdlv\kbdlv.dll                        1
 + dll\keyboard\kbdmac\kbdmac.dll                      1
 + dll\keyboard\kbdne\kbdne.dll                        1
 + dll\keyboard\kbdno\kbdno.dll                        1
 + dll\keyboard\kbdpl\kbdpl.dll                        1
 + dll\keyboard\kbdpl1\kbdpl1.dll                      1
 + dll\keyboard\kbdpo\kbdpo.dll                        1
 + dll\keyboard\kbdro\kbdro.dll                        1
 + dll\keyboard\kbdru\kbdru.dll                        1
 + dll\keyboard\kbdru1\kbdru1.dll                      1
 + dll\keyboard\kbdsg\kbdsg.dll                        1
 + dll\keyboard\kbdsk\kbdsk.dll                        1
 + dll\keyboard\kbdsk1\kbdsk1.dll                      1
 + dll\keyboard\kbdsw\kbdsw.dll                        1
 + dll\keyboard\kbdtat\kbdtat.dll                      1
 + dll\keyboard\kbdth0\kbdth0.dll                      1
 + dll\keyboard\kbdth1\kbdth1.dll                      1
 + dll\keyboard\kbdth2\kbdth2.dll                      1
 + dll\keyboard\kbdth3\kbdth3.dll                      1
 + dll\keyboard\kbdtuf\kbdtuf.dll                      1
 + dll\keyboard\kbdtuq\kbdtuq.dll                      1
 + dll\keyboard\kbduk\kbduk.dll                        1
 + dll\keyboard\kbdur\kbdur.dll                        1
 + dll\keyboard\kbdurs\kbdurs.dll                      1
 + dll\keyboard\kbdus\kbdus.dll                        1
 + dll\keyboard\kbdusa\kbdusa.dll                      1
 + dll\keyboard\kbdusl\kbdusl.dll                      1
 + dll\keyboard\kbdusr\kbdusr.dll                      1
 + dll\keyboard\kbdusx\kbdusx.dll                      1
 + dll\keyboard\kbduzb\kbduzb.dll                      1
 + dll\keyboard\kbdvntc\kbdvntc.dll                    1
 + dll\keyboard\kbdycc\kbdycc.dll                      1
 + dll\keyboard\kbdycl\kbdycl.dll                      1
 + 
 + dll\ntdll\ntdll.dll                                 1
 + 
 + dll\win32\acledit\acledit.dll                       1
 + dll\win32\aclui\aclui.dll                           1
 + dll\win32\activeds\activeds.dll                     1
 + dll\win32\actxprxy\actxprxy.dll                     1
 + dll\win32\advapi32\advapi32.dll                     1
 + dll\win32\advpack\advpack.dll                       1
 + dll\win32\atl\atl.dll                               1
 + dll\win32\authz\authz.dll                           1
 + dll\win32\avicap32\avicap32.dll                     1
 + dll\win32\avifil32\avifil32.dll                     1
 + dll\win32\batt\batt.dll                             1
 + dll\win32\bcrypt\bcrypt.dll                         1
 + dll\win32\beepmidi\beepmidi.dll                     1
 + dll\win32\browseui\browseui.dll                     1
 + dll\win32\cabinet\cabinet.dll                       1
 + dll\win32\cards\cards.dll                           1
 + dll\win32\cfgmgr32\cfgmgr32.dll                     1
 + dll\win32\clusapi\clusapi.dll                       1
 + dll\win32\comcat\comcat.dll                         1
 + dll\win32\comctl32\comctl32.dll                     1
 + dll\win32\comdlg32\comdlg32.dll                     1
 + dll\win32\compstui\compstui.dll                     1
 + dll\win32\credui\credui.dll                         1
 + dll\win32\crtdll\crtdll.dll                         1
 + dll\win32\crypt32\crypt32.dll                       1
 + dll\win32\cryptdlg\cryptdlg.dll                     1
 + dll\win32\cryptdll\cryptdll.dll                     1
 + dll\win32\cryptnet\cryptnet.dll                     1
 + dll\win32\cryptui\cryptui.dll                       1
 + dll\win32\dbghelp\dbghelp.dll                       1
 + dll\win32\dciman32\dciman32.dll                     1
 + dll\win32\devmgr\devmgr.dll                         1
 + dll\win32\dhcpcsvc\dhcpcsvc.dll                     1
 + dll\win32\dnsapi\dnsapi.dll                         1
 + dll\win32\dwmapi\dwmapi.dll                         1
 + dll\win32\faultrep\faultrep.dll                     1
 + dll\win32\fmifs\fmifs.dll                           1
 + dll\win32\fusion\fusion.dll                         1
 + dll\win32\gdi32\gdi32.dll                           1
 + dll\win32\gdiplus\gdiplus.dll                       1
 + dll\win32\getuname\getuname.dll                     1
 + dll\win32\glu32\glu32.dll                           1
 + dll\win32\hhctrl.ocx\hhctrl.ocx                     1
 + dll\win32\hid\hid.dll                               1
 + dll\win32\hlink\hlink.dll                           1
 + dll\win32\hnetcfg\hnetcfg.dll                       1
 + dll\win32\httpapi\httpapi.dll                       1
 + dll\win32\iccvid\iccvid.dll                         1
 + dll\win32\icmp\icmp.dll                             1
 + dll\win32\imaadp32.acm\imaadp32.acm                 1
 + dll\win32\imagehlp\imagehlp.dll                     1
 + dll\win32\imm32\imm32.dll                           1
 + dll\win32\inetcomm\inetcomm.dll                     1
 + dll\win32\inetmib1\inetmib1.dll                     1
 + dll\win32\initpki\initpki.dll                       1
 + dll\win32\inseng\inseng.dll                         1
 + dll\win32\iphlpapi\iphlpapi.dll                     1
 + dll\win32\itircl\itircl.dll                         1
 + dll\win32\itss\itss.dll                             1
 + dll\win32\jscript\jscript.dll                       1
 + dll\win32\kernel32\kernel32.dll                     1
 + dll\win32\loadperf\loadperf.dll                     1
 + dll\win32\localspl\localspl.dll                     1
 + dll\win32\localui\localui.dll                       1
 + dll\win32\lpk\lpk.dll                               1
 + dll\win32\lsasrv\lsasrv.dll                         1
 + dll\win32\lz32\lz32.dll                             1
 + dll\win32\mapi32\mapi32.dll                         1
 + dll\win32\mciavi32\mciavi32.dll                     1
 + dll\win32\mcicda\mcicda.dll                         1
 + dll\win32\mciqtz32\mciqtz32.dll                     1
 + dll\win32\mciseq\mciseq.dll                         1
 + dll\win32\mciwave\mciwave.dll                       1
 + dll\win32\mlang\mlang.dll                           1
 + dll\win32\mmdrv\mmdrv.dll                           1
 + dll\win32\modemui\modemui.dll                       1
 + dll\win32\mpr\mpr.dll                               1
 + dll\win32\mprapi\mprapi.dll                         1
 + dll\win32\msacm32\msacm32.dll                       1
 + dll\win32\msacm32\msacm32.drv\msacm32.drv           1
 + dll\win32\msadp32.acm\msadp32.acm                   1
 + dll\win32\msafd\msafd.dll                           1
 + dll\win32\mscat32\mscat32.dll                       1
 + dll\win32\mscms\mscms.dll                           1
 + dll\win32\mscoree\mscoree.dll                       1
 + dll\win32\msctf\msctf.dll                           1
 + dll\win32\msftedit\msftedit.dll                     1
 + dll\win32\msg711.acm\msg711.acm                     1
 + dll\win32\msgina\msgina.dll                         1
 + dll\win32\msgsm32.acm\msgsm32.acm                   1
 + dll\win32\mshtml\mshtml.dll                         1
 + dll\win32\mshtml.tlb\mshtml.tlb                     1
 + dll\win32\msi\msi.dll                               1
 + dll\win32\msimg32\msimg32.dll                       1
 + dll\win32\msimtf\msimtf.dll                         1
 + dll\win32\msisip\msisip.dll                         1
 + dll\win32\msisys.ocx\msisys.ocx                     1
 + dll\win32\msnet32\msnet32.dll                       1
 + dll\win32\msports\msports.dll                       1
 + dll\win32\msrle32\msrle32.dll                       1
 + dll\win32\mssign32\mssign32.dll                     1
 + dll\win32\mssip32\mssip32.dll                       1
 + dll\win32\mstask\mstask.dll                         1
 + dll\win32\msvcrt\msvcrt.dll                         1
 + dll\win32\msvcrt20\msvcrt20.dll                     1
 + dll\win32\msvcrt40\msvcrt40.dll                     1
 + dll\win32\msvfw32\msvfw32.dll                       1
 + dll\win32\msvidc32\msvidc32.dll                     1
 + dll\win32\mswsock\mswsock.dll                       1
 + dll\win32\msxml3\msxml3.dll                         1
 + dll\win32\nddeapi\nddeapi.dll                       1
 + dll\win32\netapi32\netapi32.dll                     1
 + dll\win32\netcfgx\netcfgx.dll                       1
 + dll\win32\netevent\netevent.dll                     1
 + dll\win32\netid\netid.dll                           1
 + dll\win32\netshell\netshell.dll                     1
 + dll\win32\newdev\newdev.dll                         1
 + dll\win32\ntdsapi\ntdsapi.dll                       1
 + dll\win32\ntlanman\ntlanman.dll                     1
 + dll\win32\ntmarta\ntmarta.dll                       1
 + dll\win32\ntprint\ntprint.dll                       1
 + dll\win32\objsel\objsel.dll                         1
 + dll\win32\odbc32\odbc32.dll                         1
 + dll\win32\odbccp32\odbccp32.dll                     1
 + dll\win32\ole32\ole32.dll                           1
 + dll\win32\oleacc\oleacc.dll                         1
 + dll\win32\oleaut32\oleaut32.dll                     1
 + dll\win32\olecli32\olecli32.dll                     1
 + dll\win32\oledlg\oledlg.dll                         1
 + dll\win32\olepro32\olepro32.dll                     1
 + dll\win32\olesvr32\olesvr32.dll                     1
 + dll\win32\olethk32\olethk32.dll                     1
 + dll\win32\opengl32\opengl32.dll                     1
 + dll\win32\pdh\pdh.dll                               1
 + dll\win32\pidgen\pidgen.dll                         1
 + dll\win32\powrprof\powrprof.dll                     1
 + dll\win32\printui\printui.dll                       1
 + dll\win32\psapi\psapi.dll                           1
 + dll\win32\pstorec\pstorec.dll                       1
 + dll\win32\qmgr\qmgr.dll                             1
 + dll\win32\qmgrprxy\qmgrprxy.dll                     1
 + dll\win32\query\query.dll                           1
 + dll\win32\rasadhlp\rasadhlp.dll                     1
 + dll\win32\rasapi32\rasapi32.dll                     1
 + dll\win32\rasdlg\rasdlg.dll                         1
 + dll\win32\rasman\rasman.dll                         1
 + dll\win32\resutils\resutils.dll                     1
 + dll\win32\riched20\riched20.dll                     1
 + dll\win32\riched32\riched32.dll                     1
 + dll\win32\rpcrt4\rpcrt4.dll                         1
 + dll\win32\rsabase\rsabase.dll                       1
 + dll\win32\rsaenh\rsaenh.dll                         1
 + dll\win32\samlib\samlib.dll                         1
 + dll\win32\samsrv\samsrv.dll                         1
 + dll\win32\sccbase\sccbase.dll                       1
 + dll\win32\schannel\schannel.dll                     1
 + dll\win32\secur32\secur32.dll                       1
 + dll\win32\security\security.dll                     1
 + dll\win32\sensapi\sensapi.dll                       1
 + dll\win32\serialui\serialui.dll                     1
 + dll\win32\setupapi\setupapi.dll                     1
 + dll\win32\sfc\sfc.dll                               1
 + dll\win32\sfc_os\sfc_os.dll                         1
 + dll\win32\shdoclc\shdoclc.dll                       1
 + dll\win32\shdocvw\shdocvw.dll                       1
 + dll\win32\shell32\shell32.dll                       1
 + dll\win32\shfolder\shfolder.dll                     1
 + dll\win32\shimgvw\shimgvw.dll                       1
 + dll\win32\shlwapi\shlwapi.dll                       1
 + dll\win32\slbcsp\slbcsp.dll                         1
 + dll\win32\smdll\smdll.dll                           1
 + dll\win32\sndblst\sndblst.dll                       1
 + dll\win32\snmpapi\snmpapi.dll                       1
 + dll\win32\softpub\softpub.dll                       1
 + dll\win32\spoolss\spoolss.dll                       1
 + dll\win32\srclient\srclient.dll                     1
 + dll\win32\stdole2.tlb\stdole2.tlb                   1
 + dll\win32\stdole32.tlb\stdole32.tlb                 1
 + dll\win32\sti\sti.dll                               1
 + dll\win32\sxs\sxs.dll                               1
 + dll\win32\syssetup\syssetup.dll                     1
 + dll\win32\t2embed\t2embed.dll                       1
 + dll\win32\tapi32\tapi32.dll                         1
 + dll\win32\tapiui\tapiui.dll                         1
 + dll\win32\traffic\traffic.dll                       1
 + dll\win32\twain_32\twain_32.dll                     1
 + dll\win32\uext2\uext2.dll                           1
 + dll\win32\ufat\ufat.dll                             1
 + dll\win32\ufatx\ufatx.dll                           1   optional
 + dll\win32\unicows\unicows.dll                       1
 + dll\win32\untfs\untfs.dll                           1
 + dll\win32\updspapi\updspapi.dll                     1
 + dll\win32\url\url.dll                               1
 + dll\win32\urlmon\urlmon.dll                         1
 + dll\win32\user32\user32.dll                         1
 + dll\win32\userenv\userenv.dll                       1
 + dll\win32\usp10\usp10.dll                           1
 + dll\win32\uxtheme\uxtheme.dll                       1
 + dll\win32\vdmdbg\vdmdbg.dll                         1
 + dll\win32\version\version.dll                       1
 + dll\win32\wdmaud.drv\wdmaud.drv                     1
 + dll\win32\wer\wer.dll                               1
 + dll\win32\windowscodecs\windowscodecs.dll           1
 + dll\win32\winemp3.acm\winemp3.acm                   1
 + dll\win32\winfax\winfax.dll                         1
 + dll\win32\wing32\wing32.dll                         1
 + dll\win32\winhttp\winhttp.dll                       1
 + dll\win32\wininet\wininet.dll                       1
 + dll\win32\winmm\winmm.dll                           1
 + dll\win32\winmm\midimap\midimap.dll                 1
 + dll\win32\winspool\winspool.drv                     1
 + dll\win32\winsta\winsta.dll                         1
 + dll\win32\wintrust\wintrust.dll                     1
 + dll\win32\wlanapi\wlanapi.dll                       1
 + dll\win32\wldap32\wldap32.dll                       1
 + dll\win32\wmi\wmi.dll                               1
 + dll\win32\ws2_32\ws2_32.dll                         1
 + dll\win32\ws2help\ws2help.dll                       1
 + dll\win32\wshirda\wshirda.dll                       1
 + dll\win32\wshtcpip\wshtcpip.dll                     1
 + dll\win32\wsock32\wsock32.dll                       1
 + dll\win32\wtsapi32\wtsapi32.dll                     1
 + dll\win32\wuapi\wuapi.dll                           1
 + dll\win32\xinput1_1\xinput1_1.dll                   1
 + dll\win32\xinput1_2\xinput1_2.dll                   1
 + dll\win32\xinput1_3\xinput1_3.dll                   1
 + dll\win32\xinput9_1_0\xinput9_1_0.dll               1
 + dll\win32\xmllite\xmllite.dll                       1
 + 
 + ; Shell Extensions
 + dll\shellext\deskadp\deskadp.dll                    1
 + dll\shellext\deskmon\deskmon.dll                    1
 + dll\shellext\devcpux\devcpux.dll                    1
 + dll\shellext\fontext\fontext.dll                    1
 + dll\shellext\slayer\slayer.dll                      1
 + 
 + ; Drivers
 + drivers\base\beep\beep.sys                          2
 + drivers\base\bootvid\bootvid.dll                    1
 + drivers\base\nmidebug\nmidebug.sys                  2
 + drivers\base\null\null.sys                          2
 + 
 + drivers\battery\battc\battc.sys                     2
 + 
 + drivers\bus\acpi\cmbatt\cmbatt.sys                  2
 + drivers\bus\acpi\compbatt\compbatt.sys              2
 + 
 + drivers\directx\dxapi\dxapi.sys                     2
 + drivers\directx\dxg\dxg.sys                         2
 + drivers\directx\dxgthk\dxgthk.sys                   2
 + 
 + drivers\filesystems\fs_rec\fs_rec.sys               2
 + drivers\filesystems\msfs\msfs.sys                   2
 + drivers\filesystems\mup\mup.sys                     2
 + drivers\filesystems\npfs\npfs.sys                   2
 + 
 + drivers\input\mouclass\mouclass.sys                 2
 + drivers\input\sermouse\sermouse.sys                 2
 + 
 + drivers\ksfilter\ks\ks.sys                          2
 + ;drivers\multimedia\bdasup\bdasup.sys                2
 + 
 + drivers\network\afd\afd.sys                         2
 + drivers\network\ndis\ndis.sys                       2
 + drivers\network\tcpip\tcpip.sys                     2
 + drivers\network\tdi\tdi.sys                         2
 + drivers\network\dd\ne2000\ne2000.sys                2
 + drivers\network\dd\pcnet\pcnet.sys                  2
 + drivers\network\ndisuio\ndisuio.sys                 2
 + 
 + drivers\serial\serenum\serenum.sys                  2
 + drivers\serial\serial\serial.sys                    2
 + 
 + drivers\storage\ide\pciide\pciide.sys               2
 + drivers\storage\ide\pciidex\pciidex.sys             2
 + 
++ drivers\hid\mouhid\mouhid.sys                       2
 + 
 + drivers\video\displays\vga\vgaddi.dll               1
 + drivers\video\displays\framebuf\framebuf.dll        1
 + drivers\video\miniport\vga\vgamp.sys                2
 + drivers\video\miniport\vbe\vbemp.sys                2
 + drivers\video\videoprt\videoprt.sys                 2
 + drivers\video\font\ftfd\ftfd.dll                    1
 + 
 + drivers\wdm\audio\filters\kmixer\kmixer.sys         2
 + drivers\wdm\audio\sysaudio\sysaudio.sys             2
 + drivers\wdm\audio\legacy\wdmaud\wdmaud.sys          2
 + drivers\wdm\audio\backpln\portcls\portcls.sys       2
 + drivers\wdm\audio\drm\drmk\drmk.sys                 2
 + drivers\wmi\wmilib.sys                              2
 + 
 + ; Media
 + media\fonts\DejaVuSans.ttf                          3
 + media\fonts\DejaVuSans-Bold.ttf                     3
 + media\fonts\DejaVuSans-BoldOblique.ttf              3
 + media\fonts\DejaVuSansMono.ttf                      3
 + media\fonts\DejaVuSansMono-Bold.ttf                 3
 + media\fonts\DejaVuSansMono-BoldOblique.ttf          3
 + media\fonts\DejaVuSansMono-Oblique.ttf              3
 + media\fonts\DejaVuSans-Oblique.ttf                  3
 + media\fonts\DejaVuSerif.ttf                         3
 + media\fonts\DejaVuSerif-Bold.ttf                    3
 + media\fonts\DejaVuSerif-BoldItalic.ttf              3
 + media\fonts\DejaVuSerif-Italic.ttf                  3
 + 
 + media\fonts\FreeMono.ttf                            3
 + media\fonts\FreeMonoBold.ttf                        3
 + media\fonts\FreeMonoBoldOblique.ttf                 3
 + media\fonts\FreeMonoOblique.ttf                     3
 + 
 + media\fonts\LiberationMono-Bold.ttf                 3
 + media\fonts\LiberationMono-BoldItalic.ttf           3
 + media\fonts\LiberationMono-Italic.ttf               3
 + media\fonts\LiberationMono-Regular.ttf              3
 + media\fonts\LiberationSans-Bold.ttf                 3
 + media\fonts\LiberationSans-BoldItalic.ttf           3
 + media\fonts\LiberationSans-Italic.ttf               3
 + media\fonts\LiberationSans-Regular.ttf              3
 + media\fonts\LiberationSerif-Bold.ttf                3
 + media\fonts\LiberationSerif-BoldItalic.ttf          3
 + media\fonts\LiberationSerif-Italic.ttf              3
 + media\fonts\LiberationSerif-Regular.ttf             3
 + 
 + media\fonts\Marlett.ttf                             3
 + media\fonts\symbol.ttf                              3
 + media\fonts\tahoma.ttf                              3
 + media\fonts\tahomabd.ttf                            3
 + 
 + media\vgafonts\vgafonts.cab                         4
 + 
 + media\nls\c_037.nls                                 1
 + media\nls\c_424.nls                                 1
 + media\nls\c_500.nls                                 1
 + media\nls\c_737.nls                                 1
 + media\nls\c_775.nls                                 1
 + media\nls\c_850.nls                                 1
 + media\nls\c_852.nls                                 1
 + media\nls\c_855.nls                                 1
 + media\nls\c_856.nls                                 1
 + media\nls\c_857.nls                                 1
 + media\nls\c_860.nls                                 1
 + media\nls\c_861.nls                                 1
 + media\nls\c_862.nls                                 1
 + media\nls\c_863.nls                                 1
 + media\nls\c_864.nls                                 1
 + media\nls\c_865.nls                                 1
 + media\nls\c_866.nls                                 1
 + media\nls\c_869.nls                                 1
 + media\nls\c_874.nls                                 1
 + media\nls\c_875.nls                                 1
 + media\nls\c_878.nls                                 1
 + media\nls\c_932.nls                                 1
 + media\nls\c_936.nls                                 1
 + media\nls\c_949.nls                                 1
 + media\nls\c_950.nls                                 1
 + media\nls\c_1006.nls                                1
 + media\nls\c_1026.nls                                1
 + media\nls\c_1250.nls                                1
 + media\nls\c_1251.nls                                1
 + media\nls\c_1253.nls                                1
 + media\nls\c_1254.nls                                1
 + media\nls\c_1255.nls                                1
 + media\nls\c_1256.nls                                1
 + media\nls\c_1257.nls                                1
 + media\nls\c_1258.nls                                1
 + media\nls\c_10000.nls                               1
 + media\nls\c_10006.nls                               1
 + media\nls\c_10007.nls                               1
 + media\nls\c_10029.nls                               1
 + media\nls\c_10079.nls                               1
 + media\nls\c_10081.nls                               1
 + media\nls\c_20866.nls                               1
 + media\nls\c_21866.nls                               1
 + media\nls\c_28591.nls                               1
 + media\nls\c_28592.nls                               1
 + media\nls\c_28593.nls                               1
 + media\nls\c_28594.nls                               1
 + media\nls\c_28595.nls                               1
 + media\nls\c_28596.nls                               1
 + media\nls\c_28597.nls                               1
 + media\nls\c_28598.nls                               1
 + media\nls\c_28599.nls                               1
 + media\nls\c_28600.nls                               1
 + media\nls\c_28603.nls                               1
 + media\nls\c_28604.nls                               1
 + media\nls\c_28605.nls                               1
 + media\nls\c_28606.nls                               1
 + media\drivers\etc\hosts                             5
 + media\drivers\etc\services                          5
 + media\inf\audio.inf                                 6
 + media\inf\acpi.inf                                  6
 + media\inf\battery.inf                               6
 + media\inf\cdrom.inf                                 6
 + media\inf\cpu.inf                                   6
 + media\inf\disk.inf                                  6
 + media\inf\display.inf                               6
 + media\inf\font.inf                                  6
 + media\inf\fdc.inf                                   6
 + media\inf\hal.inf                                   6
 + media\inf\hdc.inf                                   6
++ media\inf\input.inf                                 6
 + media\inf\intl.inf                                  6
 + media\inf\layout.inf                                6
 + media\inf\machine.inf                               6
 + media\inf\msmouse.inf                               6
 + media\inf\keyboard.inf                              6
 + media\inf\ks.inf                                    6
 + media\inf\NET_NIC.inf                               6
 + media\inf\netamd.inf                                6
 + media\inf\netisa.inf                                6
 + media\inf\netrtpnt.inf                              6
 + media\inf\nettcpip.inf                              6
 + media\inf\ports.inf                                 6
 + media\inf\scsi.inf                                  6
 + media\inf\syssetup.inf                              6
 + media\inf\unknown.inf                               6
 + media\inf\usbport.inf                               6
 + media\inf\usb.inf                                   6
 + media\inf\usbstor.inf                               6
 + media\inf\xboxdisp.inf                              6
 + 
 + 
 + ; Media Files
 + media\sounds\ReactOS_LogOn.wav                      8
 + 
 + ; Ini Files
 + boot\bootdata\system.ini                            4
 + 
 + ; Regression Testing
 + boot\bootdata\bootcdregtest\regtest.cmd             7   optional
 + 
 + ; Subsystems
 + subsystems\win32\csrss\csrss.exe                    1
 + subsystems\win32\csrss\win32csr\win32csr.dll        1
 + subsystems\win32\csrss\csrsrv\csrsrv.dll            1
 + subsystems\ntvdm\ntvdm.exe                          1   optional
 + subsystems\win32\win32k\win32k.sys                  1
 + 
 + ; Optional/proprietary files
 + modules\optional\DroidSansFallback.ttf              3  optional
 + modules\optional\NOTICE_for_Droid_Font.txt          4  optional
 + modules\optional\netkvm2k.inf                       6  optional
 + modules\optional\netkvm2k.cat                       6  optional
 + modules\optional\netkvm.sys                         2  optional
 + modules\optional\alcxwdm.inf                        6  optional
 + modules\optional\alcxwdm.sys                        2  optional
 + modules\optional\mfc42.dll                          1  optional
 + modules\optional\mfc42u.dll                         1  optional
 + modules\optional\mfc71.dll                          1  optional
 + modules\optional\mfc71u.dll                         1  optional
 + modules\optional\msvbvm50.dll                       1  optional
 + modules\optional\msvbvm60.dll                       1  optional
 + modules\optional\msvcirt.dll                        1  optional
 + modules\optional\msvcp71.dll                        1  optional
 + modules\optional\msvcr71.dll                        1  optional
 + modules\optional\vmx_fb.dll                         1  optional
 + modules\optional\vmx_mode.dll                       1  optional
 + modules\optional\vmx_svga.inf                       6  optional
 + modules\optional\vmx_svga.sys                       2  optional
 + modules\optional\wine_gecko-1.0.0-x86.cab           4  optional
 + 
 + ; Rosapps
 + modules\rosapps\applications\screensavers\cylfrac\cylfrac.scr              1   optional
 + modules\rosapps\applications\screensavers\matrix\matrix.scr                1   optional
 + modules\rosapps\applications\screensavers\blankscr\scrnsave.scr            1   optional
 + modules\rosapps\applications\screensavers\starfield\starfield.scr          1   optional
 + modules\rosapps\applications\screensavers\mazescr\mazescr.scr              1   optional
 + modules\rosapps\applications\screensavers\butterflies\butterflies.scr      1   optional
 + modules\rosapps\applications\cmdutils\comp\comp.exe                                     1   optional
 + modules\rosapps\applications\cmdutils\mode\mode.exe                                     1   optional
 + modules\rosapps\applications\cmdutils\sort\sort.exe                                     1   optional
 + modules\rosapps\applications\cmdutils\tee\tee.exe                                       1   optional
 + modules\rosapps\applications\cmdutils\touch\touch.exe                                   1   optional
 + modules\rosapps\applications\cmdutils\uptime\uptime.exe                                 1   optional
 + modules\rosapps\applications\cmdutils\y\y.exe                                           1   optional
 + modules\rosapps\applications\devutils\gdb2\gdb2.exe                                     1   optional
 + modules\rosapps\applications\devutils\gdihv\gdihv.exe                                   1   optional
 + modules\rosapps\applications\devutils\genguid\genguid.exe                               1   optional
 + modules\rosapps\applications\sysutils\gettype\gettype.exe                               1   optional
 + modules\rosapps\applications\net\ncftp\ncftp.exe                                        1   optional
 + modules\rosapps\applications\net\netreg\netreg.exe                                      1   optional
 + modules\rosapps\applications\net\niclist\niclist.exe                                    1   optional
 + modules\rosapps\applications\net\roshttpd\roshttpd.exe                                  1   optional
 + modules\rosapps\applications\notevil\notevil.exe                                        1   optional
 + modules\rosapps\applications\sysutils\chkdsk\chkdsk.exe                                 1   optional
 + modules\rosapps\applications\sysutils\systeminfo\systeminfo.exe                         1   optional
 + modules\rosapps\applications\sysutils\chklib\chklib.exe                                 1   optional
 + modules\rosapps\applications\sysutils\ctm\ctm.exe                                       1   optional
 + modules\rosapps\applications\sysutils\kill\kill.exe                                     1   optional
 + modules\rosapps\applications\sysutils\lsdd\lsdd.exe                                     1   optional
 + modules\rosapps\applications\sysutils\man\man.exe                                       1   optional
 + modules\rosapps\applications\sysutils\pedump\pedump.exe                                 1   optional
 + modules\rosapps\applications\sysutils\regexpl\regexpl.exe                               1   optional
 + modules\rosapps\applications\sysutils\tcat\tcat.exe                                     1   optional
 + modules\rosapps\applications\sysutils\tlist\tlist.exe                                   1   optional
 + modules\rosapps\applications\sysutils\screenshot\screenshot.exe                         1   optional
 + modules\rosapps\applications\sysutils\utils\binpatch\binpatch.exe                       1   optional
 + modules\rosapps\applications\sysutils\utils\cat\cat.exe                                 1   optional
 + modules\rosapps\applications\sysutils\utils\driver\load\load.exe                        1   optional
 + modules\rosapps\applications\sysutils\utils\driver\unload\unload.exe                    1   optional
 + modules\rosapps\applications\sysutils\utils\infinst\infinst.exe                         1   optional
 + modules\rosapps\applications\sysutils\utils\nts2w32err\nts2w32err.exe                   1   optional
 + modules\rosapps\applications\sysutils\utils\objdir\objdir.exe                           1   optional
 + modules\rosapps\applications\sysutils\utils\partinfo\partinfo.exe                       1   optional
 + modules\rosapps\applications\sysutils\utils\ps\ps.exe                                   1   optional
 + modules\rosapps\applications\sysutils\utils\rosperf\rosperf.exe                         1   optional
 + modules\rosapps\applications\sysutils\utils\stats\stats.exe                             1   optional
 + modules\rosapps\applications\sysutils\utils\tickcount\tickcount.exe                     1   optional
 + modules\rosapps\applications\winfile\winfile.exe                                        1   optional
 + modules\rosapps\demos\maze\maze.exe                                        1   optional
 + modules\rosapps\drivers\green\green.sys                                    2   optional
 + 
 + ; Rostests
 + modules\rostests\rosautotest\rosautotest.exe                               1   optional
 + modules\rostests\tests\pseh2\pseh2_test.exe                                7   optional
 + modules\rostests\winetests\advapi32\advapi32_winetest.exe                  7   optional
 + modules\rostests\winetests\advpack\advpack_winetest.exe                    7   optional
 + modules\rostests\winetests\amstream\amstream_winetest.exe                  7   optional
 + modules\rostests\winetests\atl\atl_winetest.exe                            7   optional
 + modules\rostests\winetests\avifil32\avifil32_winetest.exe                  7   optional
 + modules\rostests\winetests\browseui\browseui_winetest.exe                  7   optional
 + modules\rostests\winetests\cabinet\cabinet_winetest.exe                    7   optional
 + modules\rostests\winetests\comcat\comcat_winetest.exe                      7   optional
 + modules\rostests\winetests\comctl32\comctl32_winetest.exe                  7   optional
 + modules\rostests\winetests\comdlg32\comdlg32_winetest.exe                  7   optional
 + modules\rostests\winetests\credui\credui_winetest.exe                      7   optional
 + modules\rostests\winetests\crypt32\crypt32_winetest.exe                    7   optional
 + modules\rostests\winetests\cryptnet\cryptnet_winetest.exe                  7   optional
 + modules\rostests\winetests\cryptui\cryptui_winetest.exe                    7   optional
 + modules\rostests\winetests\dnsapi\dnsapi_winetest.exe                      7   optional
 + modules\rostests\winetests\dsound\dsound_winetest.exe                      7   optional
 + modules\rostests\winetests\fusion\fusion_winetest.exe                      7   optional
 + modules\rostests\winetests\gdi32\gdi32_winetest.exe                        7   optional
 + modules\rostests\winetests\gdiplus\gdiplus_winetest.exe                    7   optional
 + modules\rostests\winetests\hlink\hlink_winetest.exe                        7   optional
 + modules\rostests\winetests\icmp\icmp_winetest.exe                          7   optional
 + modules\rostests\winetests\imagehlp\imagehlp_winetest.exe                  7   optional
 + modules\rostests\winetests\imm32\imm32_winetest.exe                        7   optional
 + modules\rostests\winetests\inetcomm\inetcomm_winetest.exe                  7   optional
 + modules\rostests\winetests\inetmib1\inetmib1_winetest.exe                  7   optional
 + modules\rostests\winetests\iphlpapi\iphlpapi_winetest.exe                  7   optional
 + modules\rostests\winetests\itss\itss_winetest.exe                          7   optional
 + modules\rostests\winetests\jscript\jscript_winetest.exe                    7   optional
 + modules\rostests\winetests\kernel32\kernel32_winetest.exe                  7   optional
 + modules\rostests\winetests\localspl\localspl_winetest.exe                  7   optional
 + modules\rostests\winetests\localui\localui_winetest.exe                    7   optional
 + modules\rostests\winetests\lz32\lz32_winetest.exe                          7   optional
 + modules\rostests\winetests\mapi32\mapi32_winetest.exe                      7   optional
 + modules\rostests\winetests\mlang\mlang_winetest.exe                        7   optional
 + modules\rostests\winetests\msacm32\msacm32_winetest.exe                    7   optional
 + modules\rostests\winetests\mscms\mscms_winetest.exe                        7   optional
 + modules\rostests\winetests\mscoree\mscoree_winetest.exe                    7   optional
 + modules\rostests\winetests\msctf\msctf_winetest.exe                        7   optional
 + modules\rostests\winetests\mshtml\mshtml_winetest.exe                      7   optional
 + modules\rostests\winetests\msi\msi_winetest.exe                            7   optional
 + modules\rostests\winetests\mstask\mstask_winetest.exe                      7   optional
 + modules\rostests\winetests\msvcrt\msvcrt_winetest.exe                      7   optional
 + modules\rostests\winetests\msvcrtd\msvcrtd_winetest.exe                    7   optional
 + modules\rostests\winetests\msvfw32\msvfw32_winetest.exe                    7   optional
 + modules\rostests\winetests\msxml3\msxml3_winetest.exe                      7   optional
 + modules\rostests\winetests\netapi32\netapi32_winetest.exe                  7   optional
 + modules\rostests\winetests\ntdll\ntdll_winetest.exe                        7   optional
 + modules\rostests\winetests\ntdsapi\ntdsapi_winetest.exe                    7   optional
 + modules\rostests\winetests\ntprint\ntprint_winetest.exe                    7   optional
 + modules\rostests\winetests\odbccp32\odbccp32_winetest.exe                  7   optional
 + modules\rostests\winetests\ole32\ole32_winetest.exe                        7   optional
 + modules\rostests\winetests\oleacc\oleacc_winetest.exe                      7   optional
 + modules\rostests\winetests\oleaut32\oleaut32_winetest.exe                  7   optional
 + modules\rostests\winetests\opengl32\opengl32_winetest.exe                  7   optional
 + modules\rostests\winetests\pdh\pdh_winetest.exe                            7   optional
 + modules\rostests\winetests\powrprof\powrprof_winetest.exe                  7   optional
 + modules\rostests\winetests\psapi\psapi_winetest.exe                        7   optional
 + modules\rostests\winetests\qmgr\qmgr_winetest.exe                          7   optional
 + modules\rostests\winetests\quartz\quartz_winetest.exe                      7   optional
 + modules\rostests\winetests\rasapi32\rasapi32_winetest.exe                  7   optional
 + modules\rostests\winetests\riched20\riched20_winetest.exe                  7   optional
 + modules\rostests\winetests\riched32\riched32_winetest.exe                  7   optional
 + modules\rostests\winetests\rpcrt4\rpcrt4_winetest.exe                      7   optional
 + modules\rostests\winetests\rsabase\rsabase_winetest.exe                    7   optional
 + modules\rostests\winetests\rsaenh\rsaenh_winetest.exe                      7   optional
 + modules\rostests\winetests\schannel\schannel_winetest.exe                  7   optional
 + modules\rostests\winetests\secur32\secur32_winetest.exe                    7   optional
 + modules\rostests\winetests\serialui\serialui_winetest.exe                  7   optional
 + modules\rostests\winetests\setupapi\setupapi_winetest.exe                  7   optional
 + modules\rostests\winetests\shdocvw\shdocvw_winetest.exe                    7   optional
 + modules\rostests\winetests\shell32\shell32_winetest.exe                    7   optional
 + modules\rostests\winetests\shlwapi\shlwapi_winetest.exe                    7   optional
 + modules\rostests\winetests\snmpapi\snmpapi_winetest.exe                    7   optional
 + modules\rostests\winetests\spoolss\spoolss_winetest.exe                    7   optional
 + modules\rostests\winetests\twain_32\twain_32_winetest.exe                  7   optional
 + modules\rostests\winetests\urlmon\urlmon_winetest.exe                      7   optional
 + modules\rostests\winetests\user32\user32_winetest.exe                      7   optional
 + modules\rostests\winetests\userenv\userenv_winetest.exe                    7   optional
 + modules\rostests\winetests\usp10\usp10_winetest.exe                        7   optional
 + modules\rostests\winetests\uxtheme\uxtheme_winetest.exe                    7   optional
 + modules\rostests\winetests\version\version_winetest.exe                    7   optional
 + modules\rostests\winetests\winhttp\winhttp_winetest.exe                    7   optional
 + modules\rostests\winetests\wininet\wininet_winetest.exe                    7   optional
 + modules\rostests\winetests\winmm\winmm_winetest.exe                        7   optional
 + modules\rostests\winetests\wintrust\wintrust_winetest.exe                  7   optional
 + modules\rostests\winetests\wlanapi\wlanapi_winetest.exe                    7   optional
 + modules\rostests\winetests\wldap32\wldap32_winetest.exe                    7   optional
 + modules\rostests\winetests\ws2_32\ws2_32_winetest.exe                      7   optional
 + modules\rostests\winetests\xmllite\xmllite_winetest.exe                    7   optional
 + 
 + modules\rostests\apitests\advapi32\advapi32_apitest.exe                    7   optional
 + modules\rostests\apitests\dciman32\dciman32_apitest.exe                    7   optional
 + modules\rostests\apitests\gdi32\gdi32_apitest.exe                          7   optional
 + modules\rostests\apitests\kernel32\kernel32_apitest.exe                    7   optional
 + modules\rostests\apitests\msvcrt\msvcrt_apitest.exe                        7   optional
 + modules\rostests\apitests\ntdll\ntdll_apitest.exe                          7   optional
 + modules\rostests\apitests\user32\user32_apitest.exe                        7   optional
 + modules\rostests\apitests\ws2_32\ws2_32_apitest.exe                        7   optional
 + 
 + modules\rostests\kmtests\kmtest_.exe                                       7   optional
 + modules\rostests\kmtests\kmtest_drv.sys                                    7   optional
 + modules\rostests\kmtests\example\example_drv.sys                           7   optional
 + modules\rostests\kmtests\ntos_io\iodeviceobject_drv.sys                    7   optional
 + modules\rostests\kmtests\ntos_io\iohelper_drv.sys                          7   optional
 + 
 + modules\wallpaper\Angelus_02_ROSWP.bmp                                     4   optional
index 1b7f1c7,0000000,59668ec..59668ec
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,477 -1,0 -1,510 +1,510 @@@@
-  usbdrv.sys=,,,,,,,,,,,,4
 + [Version]
 + Signature = "$ReactOS$"
 + 
 + [Directories]
 + ; <directory_id> = <path>
 + 1 = "\"
 + 2 = system32
 + 3 = system32\config
 + 4 = system32\drivers
 + 5 = media
 + 6 = Fonts
 + 7 = bin
 + 
 + [DiskSpaceRequirements]
 + ; Required free system partition disk space in MB
 + FreeSysPartDiskSpace=350
 + 
 + [SourceDisksFiles]
 + acpi.sys=,,,,,,,,,,,,4
 + nmidebug.sys=,,,,,,x,,,,,,4
 + uniata.sys=,,,,,,x,,,,,,4
 + buslogic.sys=,,,,,,x,,,,,,4
 + blue.sys=,,,,,,x,,,,,,4
 + bootvid.dll=,,,,,,,,,,,,2
 + c_437.nls=,,,,,,,,,,,,2
 + c_1252.nls=,,,,,,,,,,,,2
 + cdfs.sys=,,,,,,x,,,,,,4
 + cdrom.sys=,,,,,,x,,,,,,4
 + class2.sys=,,,,,,x,,,,,,4
 + isapnp.sys=,,,,,,,,,,,,4
 + kdcom.dll=,,,,,,,,,,,,2
 + disk.sys=,,,,,,x,,,,,,4
 + floppy.sys=,,,,,,x,,,,,,4
 + i8042prt.sys=,,,,,,x,,,,,,4
++ hidclass.sys=,,,,,,,,,,,,4
++ hidparse.sys=,,,,,,,,,,,,4
++ hidusb.sys=,,,,,,,,,,,,4
++ usbccgp.sys=,,,,,,x,,,,,,4
++ usbd.sys=,,,,,,x,,,,,,4
++ usbhub.sys=,,,,,,x,,,,,,4
++ ;usbuhci.sys=,,,,,,x,,,,,,4
++ usbohci.sys=,,,,,,x,,,,,,4
++ usbehci.sys=,,,,,,x,,,,,,4
++ usbstor.sys=,,,,,,x,,,,,,4
++ kbdhid.sys=,,,,,,,,,,,,4
 + kbdclass.sys=,,,,,,x,,,,,,4
 + l_intl.nls=,,,,,,,,,,,,2
 + ntfs.sys=,,,,,,,,,,,,4
 + pci.sys=,,,,,,,,,,,,4
 + scsiport.sys=,,,,,,x,,,,,,4
 + fastfat.sys=,,,,,,x,,,,,,4
 + ramdisk.sys=,,,,,,x,,,,,,4
 + ext2fs.sys=,,,,,,x,,,,,,4
 + classpnp.sys=,,,,,,,,,,,,4
 + pciide.sys=,,,,,,,,,,,,4
 + pciidex.sys=,,,,,,,,,,,,4
 + pcix.sys=,,,,,,,,,,,,4
 + pcmcia.sys=,,,,,,,,,,,,4
 + swenum.sys=,,,,,,,,,,,,4
 + ntdll.dll=,,,,,,,,,,,,2
 + smss2.exe=,,,,,,,,,,,,2
 + 
 + [HardwareIdsDatabase]
 + ;*PNP0A00 = isapnp
 + *PNP0A03 = pci
 + *PNP0C08 = acpi
 + ;PCI\CC_0601 = isapnp
 + PCI\CC_0604 = pci
 + PCI\VEN_104B&CC_0100 = buslogic
 + PCI\CC_0101 = pciide
 + PCI\CC_0104 = uniata
 + PCI\CC_0105 = uniata
 + PCI\CC_0106 = uniata
 + *PNP0600 = uniata
++ USB\CLASS_09 = usbhub
++ USB\ROOT_HUB = usbhub
++ USB\ROOT_HUB20 = usbhub
++ ;PCI\CC_0C0300 = usbuhci
++ PCI\CC_0C0310 = usbohci
++ PCI\CC_0C0320 = usbehci
++ USB\Class_08&SubClass_06&Prot_50 = usbstor
++ HID_DEVICE_SYSTEM_KEYBOARD = kbdhid
++ USB\COMPOSITE = usbccgp
++ GenDisk = disk
++ USB\Class_03 = hidusb
++ GENERIC_HID_DEVICE = hidusb
 + 
 + [BootBusExtenders.Load]
 + acpi = acpi.sys
 + pci = pci.sys
 + isapnp = isapnp.sys
 + 
++ [InputDevicesSupport.Load]
++ usbehci = usbehci.sys
++ usbohci = usbohci.sys
++ ;usbuhci = usbuhci.sys
++ usbhub = usbhub.sys
++ usbccgp = usbccgp.sys
++ hidusb = hidusb.sys
++ usbstor = usbstor.sys
++ kbdhid = kbdhid.sys
++ 
 + [BusExtenders.Load]
 + pciide = pciide.sys
 + 
 + [SCSI.Load]
 + uniata = uniata.sys
 + buslogic = buslogic.sys
++ disk = disk.sys
 + 
 + [Cabinets]
 + Cabinet=reactos.cab
 + 
 + [SetupData]
 + DefaultPath = \ReactOS
 + OsLoadOptions = "/NOGUIBOOT /NODEBUG"
 + DbgOsLoadOptions = "/NOGUIBOOT /DEBUGPORT=COM1 /FIRSTCHANCE"
 + ;OsLoadOptions = "/NOGUIBOOT /DEBUGPORT=SCREEN"
 + ;OsLoadOptions = "/NOGUIBOOT /DEBUGPORT=BOCHS"
 + 
 + [NLS]
 + AnsiCodepage     = c_1252.nls
 + OemCodepage      = c_437.nls
 + UnicodeCasetable = l_intl.nls
 + DefaultLayout    = 00000409
 + DefaultLanguage  = 00000409
 + 
 + [Computer]
 + pci_up = "Standard PC Uniprocessor"
 + pci_mp = "Standard PC Multiprocessor"
 + acpi_up = "ACPI PC Uniprocessor"
 + acpi_mp = "ACPI PC Multiprocessor"
 + 
 + [Map.Computer]
 + ;<id> = <pnp id string>
 + pci_up = "PC UP"
 + pci_mp = "PC MP"
 + acpi_up = "ACPI UP"
 + acpi_mp = "ACPI MP"
 + 
 + [Files.pci_up]
 + ntoskrnl.exe=,,,,,,,,,,,,2
 + hal.dll=,,,,,,,,,,,,2
 + 
 + [Files.pci_mp]
 + ntkrnlmp.exe=,,,,,,,,,,ntoskrnl.exe,,2
 + halmps.dll=,,,,,,,,,,hal.dll,,2
 + 
 + [Files.acpi_up]
 + ntoskrnl.exe=,,,,,,,,,,,,2
 + halacpi.dll=,,,,,,,,,,hal.dll,,2
 + 
 + [Files.acpi_mp]
 + ntkrnlmp.exe=,,,,,,,,,,ntoskrnl.exe,,2
 + halacpi.dll=,,,,,,,,,,hal.dll,,2
 + 
 + [Display]
 + ;<id> = <user friendly name>,<spare>,<service key name>,<hight>,<width>,<bpp>
 + vga = "VGA Display (640x480x4)",,Vga,640,480,4
 + vbe_640x480x8 = "VESA Display (640x480x8)",,VBE,640,480,8
 + vbe_640x480x16 = "VESA Display (640x480x16)",,VBE,640,480,16
 + vbe_640x480x24 = "VESA Display (640x480x24)",,VBE,640,480,24
 + vbe_640x480x32 = "VESA Display (640x480x32)",,VBE,640,480,32
 + vbe_800x600x8 = "VESA Display (800x600x8)",,VBE,800,600,8
 + vbe = "VESA Display (800x600x16)",,VBE,800,600,16
 + vbe_800x600x24 = "VESA Display (800x600x24)",,VBE,800,600,24
 + vbe_800x600x32 = "VESA Display (800x600x32)",,VBE,800,600,32
 + vbe_1024x768x8 = "VESA Display (1024x768x8)",,VBE,1024,768,8
 + vbe_1024x768x16 = "VESA Display (1024x768x16)",,VBE,1024,768,16
 + vbe_1024x768x24 = "VESA Display (1024x768x24)",,VBE,1024,768,24
 + vbe_1024x768x32 = "VESA Display (1024x768x32)",,VBE,1024,768,32
 + vbe_1152x864x8 = "VESA Display (1152x864x8)",,VBE,1152,864,8
 + vbe_1152x864x16 = "VESA Display (1152x864x16)",,VBE,1152,864,16
 + vbe_1152x864x24 = "VESA Display (1152x864x24)",,VBE,1152,864,24
 + vbe_1152x864x32 = "VESA Display (1152x864x32)",,VBE,1152,864,32
 + vbe_1280x1024x8 = "VESA Display (1280x1024x8)",,VBE,1280,1024,8
 + vbe_1280x1024x16 = "VESA Display (1280x1024x16)",,VBE,1280,1024,16
 + vbe_1280x1024x24 = "VESA Display (1280x1024x24)",,VBE,1280,1024,24
 + vbe_1280x1024x32 = "VESA Display (1280x1024x32)",,VBE,1280,1024,32
 + vbe_1600x1200x8 = "VESA Display (1600x1200x8)",,VBE,1600,1200,8
 + vbe_1600x1200x16 = "VESA Display (1600x1200x16)",,VBE,1600,1200,16
 + vbe_1600x1200x24 = "VESA Display (1600x1200x24)",,VBE,1600,1200,24
 + vbe_1600x1200x32 = "VESA Display (1600x1200x32)",,VBE,1600,1200,32
 + 
 + [Map.Display]
 + ;<id> = <pnp id string>
 + vga = "VGA Display"
 + vbe = "VBE Display"
 + 
 + [Keyboard]
 + Default = "XT-, AT- or extended keyboard (83-105 keys)"
 + 
 + [Language]
 + ;00000436 = "Afrikaans"
 + 0000041C = "Albanian"
 + 00000401 = "Arabic (Saudi Arabia)"
 + ;00000801 = "Arabic (Iraq)"
 + ;00000C01 = "Arabic (Egypt)"
 + ;00001001 = "Arabic (Libya)"
 + ;00001401 = "Arabic (Algeria)"
 + ;00001801 = "Arabic (Morocco)"
 + ;00001C01 = "Arabic (Tunisia)"
 + ;00002001 = "Arabic (Oman)"
 + ;00002401 = "Arabic (Yemen)"
 + ;00002801 = "Arabic (Syria)"
 + ;00002C01 = "Arabic (Jordan)"
 + ;00003001 = "Arabic (Lebanon)"
 + ;00003401 = "Arabic (Kuwait)"
 + ;00003801 = "Arabic (U.A.E.)"
 + ;00003C01 = "Arabic (Bahrain)"
 + ;00004001 = "Arabic (Qatar)"
 + 0000042B = "Armenian"
 + 0000082C = "Azeri (Cyrillic)"
 + 0000042C = "Azeri (Latin)"
 + 0000042D = "Basque"
 + 00000423 = "Belarusian"
 + ;00000445 = "Bengali"
 + 00000402 = "Bulgarian"
 + ;00000455 = "Burmese"
 + 00000403 = "Catalan"
 + 00000404 = "Chinese (Taiwan)"
 + 00000804 = "Chinese (PRC)"
 + 00000C04 = "Chinese (Hong Kong S.A.R.)"
 + 00001004 = "Chinese (Singapore)"
 + 00001404 = "Chinese (Macau S.A.R.)"
 + 0000041A = "Croatian"
 + 00000405 = "Czech"
 + 00000406 = "Danish"
 + ;00000465 = "Divehi (Maldives)"
 + 00000413 = "Dutch (Netherlands)"
 + 00000813 = "Dutch (Belgium)"
 + 00000409 = "English (United States)"
 + 00000809 = "English (United Kingdom)"
 + 00000C09 = "English (Australia)"
 + 00001009 = "English (Canada)"
 + 00001409 = "English (New Zealand)"
 + 00001809 = "English (Ireland)"
 + 00001C09 = "English (South Africa)"
 + 00002009 = "English (Jamaica)"
 + 00002409 = "English (Caribbean)"
 + 00002809 = "English (Belize)"
 + 00002C09 = "English (Trinidad)"
 + 00003009 = "English (Zimbabwe)"
 + 00003409 = "English (Philippines)"
 + 0000048F = "Esperanto"
 + 00000425 = "Estonian"
 + ;00000438 = "Faeroese"
 + ;00000429 = "Farsi"
 + 0000040B = "Finnish"
 + 00000C0C = "French (Canada)"
 + 0000040C = "French (France)"
 + 0000080C = "French (Belgium)"
 + 0000100C = "French (Switzerland)"
 + 0000140C = "French (Luxembourg)"
 + 0000180C = "French (Monaco)"
 + 00000456 = "Galician (Spain)"
 + ;00000437 = "Georgian"
 + 00000407 = "German (Germany)"
 + 00000807 = "German (Switzerland)"
 + 00000C07 = "German (Austria)"
 + 00001007 = "German (Luxembourg)"
 + 00001407 = "German (Liechtenstein)"
 + 00000408 = "Greek"
 + ;00000447 = "Gujarati (India)"
 + ;0000040D = "Hebrew"
 + ;00000439 = "Hindi"
 + 0000040E = "Hungarian"
 + 0000040F = "Icelandic"
 + 00000421 = "Indonesian"
 + 00000410 = "Italian (Italy)"
 + 00000810 = "Italian (Switzerland)"
 + 00000411 = "Japanese"
 + ;0000044B = "Kannada (India)"
 + 0000043F = "Kazakh"
 + ;00000457 = "Konkani"
 + 00000412 = "Korean"
 + 00000440 = "Kyrgyz (Kyrgyzstan)"
 + 00000426 = "Latvian"
 + 00000427 = "Lithuanian"
 + 0000042F = "FYRO Macedonian"
 + ;0000083E = "Malay (Brunei Darussalam)"
 + ;0000043E = "Malay (Malaysia)"
 + ;0000044E = "Marathi"
 + ;00000450 = "Mongolian (Mongolia)"
 + 00000414 = "Norwegian (Bokmal)"
 + 00000814 = "Norwegian (Nynorsk)"
 + 00000415 = "Polish"
 + 00000816 = "Portuguese (Portugal)"
 + 00000416 = "Portuguese (Brazil)"
 + ;00000446 = "Punjabi (India)"
 + 00000418 = "Romanian"
 + 00000417 = "Romansh"
 + 00000419 = "Russian"
 + ;0000044F = "Sanskrit"
 + 00000C1A = "Serbian (Cyrillic)"
 + 0000081A = "Serbian (Latin)"
 + 0000041B = "Slovak"
 + 00000424 = "Slovenian"
 + 0000040A = "Spanish (Traditional Sort)"
 + 0000080A = "Spanish (Mexico)"
 + 00000C0A = "Spanish (International Sort)"
 + 0000100A = "Spanish (Guatemala)"
 + 0000140A = "Spanish (Costa Rica)"
 + 0000180A = "Spanish (Panama)"
 + 00001C0A = "Spanish (Dominican Republic)"
 + 0000200A = "Spanish (Venezuela)"
 + 0000240A = "Spanish (Colombia)"
 + 0000280A = "Spanish (Peru)"
 + 00002C0A = "Spanish (Argentina)"
 + 0000300A = "Spanish (Ecuador)"
 + 0000340A = "Spanish (Chile)"
 + 0000380A = "Spanish (Uruguay)"
 + 00003C0A = "Spanish (Paraguay)"
 + 0000400A = "Spanish (Bolivia)"
 + 0000440A = "Spanish (El Salvador)"
 + 0000480A = "Spanish (Honduras)"
 + 00004C0A = "Spanish (Nicaragua)"
 + 0000500A = "Spanish (Puerto Rico)"
 + ;00000441 = "Swahili"
 + 0000041D = "Swedish"
 + 0000081D = "Swedish (Finland)"
 + ;0000045A = "Syriac (Syria)"
 + ;00000449 = "Tamil"
 + 00000444 = "Tatar"
 + ;0000044A = "Telugu (India)"
 + 0000041E = "Thai"
 + 0000041F = "Turkish"
 + 00000422 = "Ukrainian"
 + ;00000420 = "Urdu"
 + 00000443 = "Uzbek (Latin)"
 + 00000843 = "Uzbek (Cyrillic)"
 + ;0000042A = "Vietnamese"
 + 00000490 = "Walon"
 + ;00000435 = "Zulu"
 + 
 + 
 + [KeyboardLayout]
 + 0000041C = "Albanian"
 + 00000401 = "Arabic (101)"
 + 00010401 = "Arabic (102)"
 + 00020401 = "Arabic (102) AZERTY"
 + 0000042B = "Armenian Eastern"
 + 0001042B = "Armenian Western"
 + 0000044D = "Assamese (Inscript)"
 + 0000082C = "Azeri Cyrillic"
 + 0000042C = "Azeri Latin"
 + 00000423 = "Belarusian"
 + 00000445 = "Bengali"
 + 00000402 = "Bulgarian BDS 5237-1978"
 + 00020402 = "Bulgarian phonetic classic"
 + 00030402 = "Bulgarian phonetic BDS 5237-2006"
 + 00000455 = "Burmese"
 + 00000C0C = "Canadian French (Legacy)"
 + 00011009 = "Canadian Multilingual Standard"
 + 0000041A = "Croatian"
 + 00000405 = "Czech"
 + 00010405 = "Czech (QWERTY)"
 + 00000406 = "Danish (Denmark)"
 + 00000439 = "Devanagari - INSCRIPT"
 + 00000413 = "Dutch"
 + 00000813 = "Dutch (Belgium)"
 + 00000809 = "English (United Kingdom)"
 + 00000409 = "English (USA)"
 + 00010409 = "English (USA-Dvorak)"
 + 00000425 = "Estonian"
 + 0000040B = "Finnish"
 + 0000080C = "French (Belgium)"
 + 0000040C = "French (France)"
 + 00000437 = "Georgian"
 + 00000407 = "German (Germany)"
 + 00030407 = "German (de_ergo)"
 + 00020407 = "German (NEO-1.1)"
 + 00010407 = "German (Ristome)"
 + 00000807 = "German (Swiss)"
 + 00000408 = "Greek"
 + 00010408 = "Greek 220"
 + 00000447 = "Gujarati"
 + 0000040D = "Hebrew"
 + 0000040E = "Hungarian"
 + 0000040F = "Icelandic"
 + 00001809 = "Irish"
 + 00000410 = "Italian"
 + 00000411 = "Japanese"
 + 00000412 = "Korean"
 + 0000043F = "Kazakh"
 + 0000080A = "Latin American"
 + 00000426 = "Latvian"
 + 00010427 = "Lithuanian"
 + 0000042F = "Macedonian (FYRO)"
 + 0000044C = "Malayalam"
 + 00000414 = "Norwegian"
 + 00000415 = "Polish (programmer's)"
 + 00010415 = "Polish (214)"
 + 00010416 = "Portuguese (Brazilian ABNT2)"
 + 00000816 = "Portuguese (Portugal)"
 + 00000418 = "Romanian"
 + 00000419 = "Russian"
 + 00010419 = "Russian (Typewriter)"
 + 00000C1A = "Serbian (Cyrillic)"
 + 0000081A = "Serbian (Latin)"
 + 0000041B = "Slovak (QWERTZ)"
 + 0001041B = "Slovak (QWERTY)"
 + 0000040A = "Spanish (traditional short)"
 + 0000041D = "Swedish (Sweden)"
 + 00000444 = "Tatar"
 + 0000041E = "Thai Kedmanee"
 + 0001041E = "Thai Pattachote"
 + 0002041E = "Thai Kedmanee (non-ShiftLock)"
 + 0003041E = "Thai Pattachote (non-ShiftLock)"
 + 0000041F = "Turkish Q"
 + 0001041F = "Turkish F"
 + 00000422 = "Ukrainian"
 + 00010422 = "Ukrainian (Student)"
 + 00030409 = "US Dvorak for left hand"
 + 00040409 = "US Dvorak for right hand"
 + 00050409 = "US English (IBM Arabic 238_L)"
 + 00020409 = "US International"
 + 00000843 = "Uzbek (Cyrillic)"
 + 0000042A = "Vietnamese"
 + 
 + [Files.KeyboardLayout]
 + 00000401 = kbda1.dll
 + 00010401 = kbda2.dll
 + 00020401 = kbda3.dll
 + 00020402 = kbdbgt.dll
 + 00030402 = kbdbga.dll
 + 00040402 = kbdbgm.dll
 + 00000405 = kbdcz.dll
 + 00010405 = kbdcz1.dll
 + 00000406 = kbdda.dll
 + 00000407 = kbdgr.dll
 + 00000807 = kbdsg.dll
 + 00010407 = kbdgrist.dll
 + 00020407 = kbdgneo.dll
 + 00030407 = kbdgerg.dll
 + 00000408 = kbdhe.dll
 + 00010408 = kbdhe.dll
 + 00000409 = kbdus.dll
 + 00000809 = kbduk.dll
 + 00001809 = kbdir.dll
 + 00010409 = kbddv.dll
 + 00011009 = kbdcan.dll
 + 00020409 = kbdusx.dll
 + 00030409 = kbdusl.dll
 + 00040409 = kbdusr.dll
 + 00050409 = kbdusa.dll
 + 0000040A = kbdes.dll
 + 0000080A = kbdla.dll
 + 0000040B = kbdfi.dll
 + 0000040C = kbdfr.dll
 + 0000080C = kbdbe.dll
 + 00000C0C = kbdfc.dll
 + 0000040D = kbdheb.dll
 + 0000040E = kbdhu.dll
 + 0000040F = kbdic.dll
 + 00000410 = kbdit.dll
 + 00000411 = kbdja.dll
 + 00000412 = kbdko.dll
 + 00000413 = kbdne.dll
 + 00000813 = kbdbe.dll
 + 00000414 = kbdno.dll
 + 00000415 = kbdpl1.dll
 + 00000816 = kbdpo.dll
 + 00010416 = kbdbr.dll
 + 00000418 = kbdro.dll
 + 00000419 = kbdru.dll
 + 00010419 = kbdru1.dll
 + 0000041A = kbdcr.dll
 + 0000081A = kbdycl.dll
 + 00000C1A = kbdycc.dll
 + 0000041B = kbdsk.dll
 + 0001041B = kbdsk1.dll
 + 0000041C = kbdal.dll
 + 0000041D = kbdsw.dll
 + 0000041E = kbdth0.dll
 + 0001041E = kbdth1.dll
 + 0002041E = kbdth2.dll
 + 0003041E = kbdth3.dll
 + 0000041F = kbdtuq.dll
 + 0001041F = kbdtuf.dll
 + 00000422 = kbdur.dll
 + 00010422 = kbdurs.dll
 + 00000423 = kbdblr.dll
 + 00000425 = kbdest.dll
 + 00000426 = kbdlv.dll
 + 00010427 = kbdlt1.dll
 + 0000042A = kbdvntc.dll
 + 0000042B = kbdarme.dll
 + 0001042B = kbdarmw.dll
 + 0000042C = kbdazel.dll
 + 0000082C = kbdaze.dll
 + 0000042F = kbdmac.dll
 + 00000437 = kbdgeo.dll
 + 00000439 = kbdindev.dll
 + 0000043F = kbdkaz.dll
 + 00000843 = kbduzb.dll
 + 00000444 = kbdtat.dll
 + 00000445 = kbdinben.dll
 + 00000447 = kbdinguj.dll
 + 0000044C = kbdinmal.dll
 + 0000044D = kbdinasa.dll
 + 00000455 = kbdbur.dll
 + 
 + [HiveInfs.Install]
 + AddReg=hivecls.inf,AddReg
 + AddReg=hivedef.inf,AddReg
 + AddReg=hivesft.inf,AddReg
 + AddReg=hivesys.inf,AddReg
 + 
 + ; EOF
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 4e3c60f,0000000,15b36ea..15b36ea
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,61 -1,0 -1,67 +1,67 @@@@
 + <?xml version="1.0"?>
 + <!DOCTYPE group SYSTEM "../tools/rbuild/project.dtd">
 + <group xmlns:xi="http://www.w3.org/2001/XInclude">
 + <directory name="base">
 +      <xi:include href="base/directory.rbuild" />
 + </directory>
 + <directory name="battery">
 +      <xi:include href="battery/directory.rbuild" />
 + </directory>
 + <directory name="bluetooth">
 +      <xi:include href="bluetooth/directory.rbuild" />
 + </directory>
 + <directory name="bus">
 +      <xi:include href="bus/directory.rbuild" />
 + </directory>
 + <directory name="directx">
 +      <xi:include href="directx/directory.rbuild" />
 + </directory>
 + <directory name="filesystems">
 +      <xi:include href="filesystems/directory.rbuild" />
 + </directory>
++ <directory name="hid">
++      <xi:include href="hid/directory.rbuild" />
++ </directory>
++ <directory name="filters>
++      <xi:include href="filters/directory.rbuild" />
++ </directory>
 + <directory name="input">
 +      <xi:include href="input/directory.rbuild" />
 + </directory>
 + <directory name="ksfilter">
 +      <xi:include href="ksfilter/directory.rbuild" />
 + </directory>
 + <directory name="multimedia">
 +      <xi:include href="multimedia/directory.rbuild" />
 + </directory>
 + <directory name="network">
 +      <xi:include href="network/directory.rbuild" />
 + </directory>
 + <directory name="parallel">
 +      <xi:include href="parallel/directory.rbuild" />
 + </directory>
 + <directory name="sac">
 +     <xi:include href="sac/directory.rbuild" />
 + </directory>
 + <directory name="serial">
 +      <xi:include href="serial/directory.rbuild" />
 + </directory>
 + <directory name="setup">
 +      <xi:include href="setup/directory.rbuild" />
 + </directory>
 + <directory name="storage">
 +      <xi:include href="storage/directory.rbuild" />
 + </directory>
 + <directory name="usb">
 +      <xi:include href="usb/directory.rbuild" />
 + </directory>
 + <directory name="video">
 +      <xi:include href="video/directory.rbuild" />
 + </directory>
 + <directory name="wdm">
 +      <xi:include href="wdm/wdm.rbuild" />
 + </directory>
 + <directory name="wmi">
 +      <xi:include href="wmi/wmilib.rbuild" />
 + </directory>
 + </group>
index 0000000,0000000,4a99868..4a99868
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,0000000..06c6119
new file mode 100644 (file)
--- /dev/null
--- /dev/null
--- /dev/null
@@@@ -1,0 -1,0 -1,0 +1,453 @@@@
+++#ifndef _MNTMGR_H_
+++#define _MNTMGR_H_
+++
+++#include <ntifs.h>
+++#include <ntddk.h>
+++#include <mountdev.h>
+++#include <ntddvol.h>
+++#include <wdmguid.h>
+++#include <ioevent.h>
+++#include <psfuncs.h>
+++#include <ntdddisk.h>
+++#include <ntddvol.h>
+++
+++/* Enter FIXME */
+++#ifdef IsEqualGUID
+++#undef IsEqualGUID
+++#endif
+++
+++#define IsEqualGUID(rguid1, rguid2) (!RtlCompareMemory(rguid1, rguid2, sizeof(GUID)))
+++
+++#define FILE_READ_PROPERTIES  0x00000008
+++#define FILE_WRITE_PROPERTIES 0x00000010
+++
+++#define GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER 0x80000000
+++/* Leave FIXME */
+++
+++typedef struct _DEVICE_EXTENSION
+++{
+++    PDEVICE_OBJECT DeviceObject;           // 0x0
+++    PDRIVER_OBJECT DriverObject;           // 0x4
+++    LIST_ENTRY DeviceListHead;             // 0x8
+++    LIST_ENTRY OfflineDeviceListHead;      // 0x10
+++    PVOID NotificationEntry;               // 0x18
+++    KSEMAPHORE DeviceLock;                 // 0x1C
+++    KSEMAPHORE RemoteDatabaseLock;         // 0x30
+++    ULONG AutomaticDriveLetter;            // 0x44
+++    LIST_ENTRY IrpListHead;                // 0x48
+++    ULONG EpicNumber;                      // 0x50
+++    LIST_ENTRY SavedLinksListHead;         // 0x54
+++    BOOLEAN ProcessedSuggestions;          // 0x5C
+++    BOOLEAN NoAutoMount;                   // 0x5D
+++    LIST_ENTRY WorkerQueueListHead;        // 0x60
+++    KSEMAPHORE WorkerSemaphore;            // 0x68
+++    LONG WorkerReferences;                 // 0x7C
+++    KSPIN_LOCK WorkerLock;                 // 0x80
+++    LIST_ENTRY UniqueIdWorkerItemListHead; // 0x84
+++    PMOUNTDEV_UNIQUE_ID DriveLetterData;   // 0x8C
+++    UNICODE_STRING RegistryPath;           // 0x90
+++    LONG WorkerThreadStatus;               // 0x98
+++    LIST_ENTRY OnlineNotificationListHead; // 0x9C
+++    ULONG OnlineNotificationWorkerActive;  // 0xA4
+++    ULONG OnlineNotificationCount;         // 0xA8
+++    KEVENT OnlineNotificationEvent;        // 0xAC
+++} DEVICE_EXTENSION, *PDEVICE_EXTENSION;    // 0xBC
+++
+++typedef struct _DEVICE_INFORMATION
+++{
+++    LIST_ENTRY DeviceListEntry;             // 0x00
+++    LIST_ENTRY SymbolicLinksListHead;       // 0x08
+++    LIST_ENTRY ReplicatedUniqueIdsListHead; // 0x10
+++    LIST_ENTRY AssociatedDevicesHead;       // 0x18
+++    UNICODE_STRING SymbolicName;            // 0x20
+++    PMOUNTDEV_UNIQUE_ID UniqueId;           // 0x28
+++    UNICODE_STRING DeviceName;              // 0x2C
+++    BOOLEAN KeepLinks;                      // 0x34
+++    UCHAR SuggestedDriveLetter;             // 0x35
+++    BOOLEAN Volume;                         // 0x36
+++    BOOLEAN Removable;                      // 0x37
+++    BOOLEAN LetterAssigned;                 // 0x38
+++    BOOLEAN NeedsReconcile;                 // 0x39
+++    BOOLEAN NoDatabase;                     // 0x3A
+++    BOOLEAN SkipNotifications;              // 0x3B
+++    ULONG Migrated;                         // 0x3C
+++    LONG MountState;                        // 0x40
+++    PVOID TargetDeviceNotificationEntry;    // 0x44
+++    PDEVICE_EXTENSION DeviceExtension;      // 0x48
+++} DEVICE_INFORMATION, *PDEVICE_INFORMATION; // 0x4C
+++
+++typedef struct _SYMLINK_INFORMATION
+++{
+++    LIST_ENTRY SymbolicLinksListEntry;        // 0x00
+++    UNICODE_STRING Name;                      // 0x08
+++    BOOLEAN Online;                           // 0x10
+++} SYMLINK_INFORMATION, *PSYMLINK_INFORMATION; // 0x14
+++
+++typedef struct _SAVED_LINK_INFORMATION
+++{
+++    LIST_ENTRY SavedLinksListEntry;                 // 0x0
+++    LIST_ENTRY SymbolicLinksListHead;               // 0x8
+++    PMOUNTDEV_UNIQUE_ID UniqueId;                   // 0x10
+++} SAVED_LINK_INFORMATION, *PSAVED_LINK_INFORMATION; // 0x14
+++
+++typedef struct _UNIQUE_ID_REPLICATE
+++{
+++    LIST_ENTRY ReplicatedUniqueIdsListEntry;  // 0x0
+++    PMOUNTDEV_UNIQUE_ID UniqueId;             // 0x8
+++} UNIQUE_ID_REPLICATE, *PUNIQUE_ID_REPLICATE; // 0xC
+++
+++typedef struct _DATABASE_ENTRY
+++{
+++    ULONG EntrySize;                // 0x00
+++    ULONG DatabaseOffset;           // 0x04
+++    USHORT SymbolicNameOffset;      // 0x08
+++    USHORT SymbolicNameLength;      // 0x0A
+++    USHORT UniqueIdOffset;          // 0x0C
+++    USHORT UniqueIdLength;          // 0x0E
+++} DATABASE_ENTRY, *PDATABASE_ENTRY; // 0x10
+++
+++typedef struct _ASSOCIATED_DEVICE_ENTRY
+++{
+++    LIST_ENTRY AssociatedDevicesEntry;                // 0x00
+++    PDEVICE_INFORMATION DeviceInformation;            // 0x08
+++    UNICODE_STRING String;                            // 0x0C
+++} ASSOCIATED_DEVICE_ENTRY, *PASSOCIATED_DEVICE_ENTRY; // 0x14
+++
+++typedef struct _ONLINE_NOTIFICATION_WORK_ITEM
+++{
+++    WORK_QUEUE_ITEM;                                              // 0x00
+++    PDEVICE_EXTENSION DeviceExtension;                            // 0x10
+++    UNICODE_STRING SymbolicName;                                  // 0x14
+++} ONLINE_NOTIFICATION_WORK_ITEM, *PONLINE_NOTIFICATION_WORK_ITEM; // 0x1C
+++
+++typedef struct _RECONCILE_WORK_ITEM
+++{
+++    LIST_ENTRY WorkerQueueListEntry;            // 0x00
+++    PIO_WORKITEM WorkItem;                      // 0x08
+++    PWORKER_THREAD_ROUTINE WorkerRoutine;       // 0x0C
+++    PVOID Context;                              // 0x10
+++    PDEVICE_EXTENSION DeviceExtension;          // 0x14
+++    PDEVICE_INFORMATION DeviceInformation;      // 0x18
+++} RECONCILE_WORK_ITEM, *PRECONCILE_WORK_ITEM;   // 0x1C
+++
+++typedef struct _MIGRATE_WORK_ITEM
+++{
+++    PIO_WORKITEM WorkItem;                 // 0x0
+++    PDEVICE_INFORMATION DeviceInformation; // 0x4
+++    PKEVENT Event;                         // 0x8
+++    NTSTATUS Status;                       // 0x0C
+++    HANDLE Database;                       // 0x10
+++} MIGRATE_WORK_ITEM, *PMIGRATE_WORK_ITEM;  // 0x14
+++
+++typedef struct _UNIQUE_ID_WORK_ITEM
+++{
+++    LIST_ENTRY UniqueIdWorkerItemListEntry;   // 0x0
+++    PIO_WORKITEM WorkItem;                    // 0x8
+++    PDEVICE_EXTENSION DeviceExtension;        // 0xC
+++    PIRP Irp;                                 // 0x10
+++    PVOID IrpBuffer;                          // 0x14
+++    PKEVENT Event;                            // 0x1C
+++    UNICODE_STRING DeviceName;                // 0x20
+++    ULONG IrpBufferLength;                    // 0x28
+++    ULONG StackSize;                          // 0x2C
+++} UNIQUE_ID_WORK_ITEM, *PUNIQUE_ID_WORK_ITEM; // 0x30
+++
+++PDEVICE_OBJECT gdeviceObject;
+++
+++/* Memory allocation helpers */
+++#define AllocatePool(Size) ExAllocatePoolWithTag(PagedPool, Size, 'AtnM')
+++#define FreePool(P)        ExFreePoolWithTag(P, 'AtnM')
+++
+++/* Misc macros */
+++#define MAX(a, b)          ((a > b) ? a : b)
+++
+++#define LETTER_POSITION     0xC
+++#define COLON_POSITION      0xD
+++#define DRIVE_LETTER_LENGTH 0x1C
+++
+++/* mountmgr.c */
+++
+++extern UNICODE_STRING DosDevicesMount;
+++extern UNICODE_STRING ReparseIndex;
+++extern UNICODE_STRING DeviceFloppy;
+++extern UNICODE_STRING DeviceMount;
+++extern UNICODE_STRING DeviceCdRom;
+++extern UNICODE_STRING SafeVolumes;
+++extern UNICODE_STRING DosDevices;
+++extern UNICODE_STRING DosGlobal;
+++extern UNICODE_STRING Global;
+++extern UNICODE_STRING Volume;
+++extern KEVENT UnloadEvent;
+++extern LONG Unloading;
+++
+++DRIVER_INITIALIZE DriverEntry;
+++
+++VOID
+++NTAPI
+++MountMgrCancel(
+++    IN PDEVICE_OBJECT DeviceObject,
+++    IN PIRP Irp
+++);
+++
+++NTSTATUS
+++MountMgrMountedDeviceArrival(
+++    IN PDEVICE_EXTENSION Extension,
+++    IN PUNICODE_STRING SymbolicName,
+++    IN BOOLEAN FromVolume
+++);
+++
+++VOID
+++MountMgrMountedDeviceRemoval(
+++    IN PDEVICE_EXTENSION Extension,
+++    IN PUNICODE_STRING DeviceName
+++);
+++
+++NTSTATUS
+++FindDeviceInfo(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PUNICODE_STRING SymbolicName,
+++    IN BOOLEAN DeviceNameGiven,
+++    OUT PDEVICE_INFORMATION * DeviceInformation
+++);
+++
+++VOID
+++MountMgrFreeDeadDeviceInfo(
+++    IN PDEVICE_INFORMATION DeviceInformation
+++);
+++
+++NTSTATUS
+++QueryDeviceInformation(
+++    IN PUNICODE_STRING SymbolicName,
+++    OUT PUNICODE_STRING DeviceName OPTIONAL,
+++    OUT PMOUNTDEV_UNIQUE_ID * UniqueId OPTIONAL,
+++    OUT PBOOLEAN Removable OPTIONAL,
+++    OUT PBOOLEAN GptDriveLetter OPTIONAL,
+++    OUT PBOOLEAN HasGuid OPTIONAL,
+++    IN OUT LPGUID StableGuid OPTIONAL,
+++    OUT PBOOLEAN Valid OPTIONAL
+++);
+++
+++BOOLEAN
+++HasDriveLetter(
+++    IN PDEVICE_INFORMATION DeviceInformation
+++);
+++
+++/* database.c */
+++
+++extern PWSTR DatabasePath;
+++extern PWSTR OfflinePath;
+++
+++VOID
+++ReconcileThisDatabaseWithMaster(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PDEVICE_INFORMATION DeviceInformation
+++);
+++
+++NTSTATUS
+++WaitForRemoteDatabaseSemaphore(
+++    IN PDEVICE_EXTENSION DeviceExtension
+++);
+++
+++VOID
+++ReleaseRemoteDatabaseSemaphore(
+++    IN PDEVICE_EXTENSION DeviceExtension
+++);
+++
+++VOID
+++ChangeRemoteDatabaseUniqueId(
+++    IN PDEVICE_INFORMATION DeviceInformation,
+++    IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
+++    IN PMOUNTDEV_UNIQUE_ID NewUniqueId
+++);
+++
+++VOID
+++ReconcileAllDatabasesWithMaster(
+++    IN PDEVICE_EXTENSION DeviceExtension
+++);
+++
+++VOID
+++DeleteFromLocalDatabase(
+++    IN PUNICODE_STRING SymbolicLink,
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId
+++);
+++
+++VOID
+++DeleteRegistryDriveLetter(
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId
+++);
+++
+++VOID
+++DeleteNoDriveLetterEntry(
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId
+++);
+++
+++NTSTATUS
+++QueryVolumeName(
+++    IN HANDLE RootDirectory,
+++    IN PFILE_REPARSE_POINT_INFORMATION ReparsePointInformation,
+++    IN PUNICODE_STRING FileName OPTIONAL,
+++    OUT PUNICODE_STRING SymbolicName,
+++    OUT PUNICODE_STRING VolumeName
+++);
+++
+++/* device.c */
+++
+++DRIVER_DISPATCH MountMgrDeviceControl;
+++
+++/* notify.c */
+++VOID
+++IssueUniqueIdChangeNotifyWorker(
+++    IN PUNIQUE_ID_WORK_ITEM WorkItem,
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId
+++);
+++
+++VOID
+++WaitForOnlinesToComplete(
+++    IN PDEVICE_EXTENSION DeviceExtension
+++);
+++
+++VOID
+++RegisterForTargetDeviceNotification(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PDEVICE_INFORMATION DeviceInformation
+++);
+++
+++VOID
+++SendOnlineNotification(
+++    IN PUNICODE_STRING SymbolicName
+++);
+++
+++VOID
+++IssueUniqueIdChangeNotify(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PUNICODE_STRING DeviceName,
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId
+++);
+++
+++VOID
+++PostOnlineNotification(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PUNICODE_STRING SymbolicName
+++);
+++
+++VOID
+++MountMgrNotify(
+++    IN PDEVICE_EXTENSION DeviceExtension
+++);
+++
+++VOID
+++MountMgrNotifyNameChange(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PUNICODE_STRING DeviceName,
+++    IN BOOLEAN ValidateVolume
+++);
+++
+++/* uniqueid.c */
+++VOID
+++MountMgrUniqueIdChangeRoutine(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PMOUNTDEV_UNIQUE_ID OldUniqueId,
+++    IN PMOUNTDEV_UNIQUE_ID NewUniqueId
+++);
+++
+++VOID
+++CreateNoDriveLetterEntry(
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId
+++);
+++
+++BOOLEAN
+++HasNoDriveLetterEntry(
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId
+++);
+++
+++/* point.c */
+++NTSTATUS
+++MountMgrCreatePointWorker(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PUNICODE_STRING SymbolicLinkName,
+++    IN PUNICODE_STRING DeviceName
+++);
+++
+++NTSTATUS
+++QueryPointsFromSymbolicLinkName(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PUNICODE_STRING SymbolicName,
+++    IN PIRP Irp
+++);
+++
+++NTSTATUS
+++QueryPointsFromMemory(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PIRP Irp,
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL,
+++    IN PUNICODE_STRING SymbolicName OPTIONAL
+++);
+++
+++/* symlink.c */
+++NTSTATUS
+++GlobalCreateSymbolicLink(
+++    IN PUNICODE_STRING DosName,
+++    IN PUNICODE_STRING DeviceName
+++);
+++
+++NTSTATUS
+++GlobalDeleteSymbolicLink(
+++    IN PUNICODE_STRING DosName
+++);
+++
+++NTSTATUS
+++QuerySuggestedLinkName(
+++    IN PUNICODE_STRING SymbolicName,
+++    OUT PUNICODE_STRING SuggestedLinkName,
+++    OUT PBOOLEAN UseOnlyIfThereAreNoOtherLinks
+++);
+++
+++NTSTATUS
+++QuerySymbolicLinkNamesFromStorage(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PDEVICE_INFORMATION DeviceInformation,
+++    IN PUNICODE_STRING SuggestedLinkName,
+++    IN BOOLEAN UseOnlyIfThereAreNoOtherLinks,
+++    OUT PUNICODE_STRING * SymLinks,
+++    OUT PULONG SymLinkCount,
+++    IN BOOLEAN HasGuid,
+++    IN LPGUID Guid
+++);
+++
+++PSAVED_LINK_INFORMATION
+++RemoveSavedLinks(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PMOUNTDEV_UNIQUE_ID UniqueId
+++);
+++
+++BOOLEAN
+++RedirectSavedLink(
+++    IN PSAVED_LINK_INFORMATION SavedLinkInformation,
+++    IN PUNICODE_STRING DosName,
+++    IN PUNICODE_STRING NewLink
+++);
+++
+++VOID
+++SendLinkCreated(
+++    IN PUNICODE_STRING SymbolicName
+++);
+++
+++NTSTATUS
+++CreateNewVolumeName(
+++    OUT PUNICODE_STRING VolumeName,
+++    IN PGUID VolumeGuid OPTIONAL
+++);
+++
+++BOOLEAN
+++IsDriveLetter(
+++    PUNICODE_STRING SymbolicName
+++);
+++
+++VOID
+++DeleteSymbolicLinkNameFromMemory(
+++    IN PDEVICE_EXTENSION DeviceExtension,
+++    IN PUNICODE_STRING SymbolicLink,
+++    IN BOOLEAN MarkOffline
+++);
+++
+++#endif /* _MNTMGR_H_ */
index 0000000,0000000,0000000..b805a20
new file mode 100644 (file)
--- /dev/null
--- /dev/null
--- /dev/null
@@@@ -1,0 -1,0 -1,0 +1,1896 @@@@
+++/*
+++ *  ReactOS kernel
+++ *  Copyright (C) 2011 ReactOS Team
+++ *
+++ *  This program is free software; you can redistribute it and/or modify
+++ *  it under the terms of the GNU General Public License as published by
+++ *  the Free Software Foundation; either version 2 of the License, or
+++ *  (at your option) any later version.
+++ *
+++ *  This program is distributed in the hope that it will be useful,
+++ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+++ *  GNU General Public License for more details.
+++ *
+++ *  You should have received a copy of the GNU General Public License
+++ *  along with this program; if not, write to the Free Software
+++ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+++ *
+++ * COPYRIGHT:        See COPYING in the top level directory
+++ * PROJECT:          ReactOS kernel
+++ * FILE:             drivers/filesystem/mountmgr/mountmgr.c
+++ * PURPOSE:          Mount Manager
+++ * PROGRAMMER:       Pierre Schweitzer (pierre.schweitzer@reactos.org)
+++ *                   Alex Ionescu (alex.ionescu@reactos.org)
+++ */
+++
+++/* INCLUDES *****************************************************************/
+++
+++#include "mntmgr.h"
+++
+++#define NDEBUG
+++#include <debug.h>
+++
+++/* FIXME */
+++GUID MountedDevicesGuid = {0x53F5630D, 0xB6BF, 0x11D0, {0x94, 0xF2, 0x00, 0xA0, 0xC9, 0x1E, 0xFB, 0x8B}};
+++
+++KEVENT UnloadEvent;
+++LONG Unloading;
+++
+++PWSTR Cunc = L"\\??\\C:";
+++
+++/*
+++ * TODO:
+++ * - MountMgrQueryDosVolumePath
+++ * - MountMgrQueryDosVolumePaths
+++ * - MountMgrQueryVolumePaths
+++ * - MountMgrValidateBackPointer
+++ * - MountMgrVolumeMountPointCreated
+++ * - MountMgrVolumeMountPointDeleted
+++ * - ReconcileThisDatabaseWithMasterWorker
+++ */
+++
+++/*
+++ * @implemented
+++ */
+++BOOLEAN
+++IsOffline(PUNICODE_STRING SymbolicName)
+++{
+++    NTSTATUS Status;
+++    ULONG IsOffline, Default;
+++    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+++
+++    /* Prepare to look in the registry to see if
+++     * given volume is offline
+++     */
+++    RtlZeroMemory(QueryTable, sizeof(QueryTable));
+++    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+++    QueryTable[0].Name = SymbolicName->Buffer;
+++    QueryTable[0].EntryContext = &IsOffline;
+++    QueryTable[0].DefaultType = REG_DWORD;
+++    QueryTable[0].DefaultLength = sizeof(ULONG);
+++    QueryTable[0].DefaultData = &Default;
+++
+++    Default = 0;
+++
+++    /* Query status */
+++    Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+++                                    OfflinePath,
+++                                    QueryTable,
+++                                    NULL,
+++                                    NULL);
+++    if (!NT_SUCCESS(Status))
+++    {
+++        IsOffline = 0;
+++    }
+++
+++    return (IsOffline != 0);
+++}
+++
+++/*
+++ * @implemented
+++ */
+++BOOLEAN
+++HasDriveLetter(IN PDEVICE_INFORMATION DeviceInformation)
+++{
+++    PLIST_ENTRY NextEntry;
+++    PSYMLINK_INFORMATION SymlinkInfo;
+++
+++    /* To have a drive letter, a device must have symbolic links */
+++    if (IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
+++    {
+++        return FALSE;
+++    }
+++
+++    /* Browse all the links untill a drive letter is found */
+++    NextEntry = &(DeviceInformation->SymbolicLinksListHead);
+++    do
+++    {
+++        SymlinkInfo = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+++
+++        if (SymlinkInfo->Online)
+++        {
+++            if (IsDriveLetter(&(SymlinkInfo->Name)))
+++            {
+++                return TRUE;
+++            }
+++        }
+++
+++        NextEntry = NextEntry->Flink;
+++    } while (NextEntry != &(DeviceInformation->SymbolicLinksListHead));
+++
+++    return FALSE;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++NTSTATUS
+++CreateNewDriveLetterName(OUT PUNICODE_STRING DriveLetter,
+++                         IN PUNICODE_STRING DeviceName,
+++                         IN UCHAR Letter,
+++                         IN PMOUNTDEV_UNIQUE_ID UniqueId OPTIONAL)
+++{
+++    NTSTATUS Status;
+++
+++    /* Allocate a big enough buffer to contain the symbolic link */
+++    DriveLetter->MaximumLength = sizeof(DosDevices.Buffer) + 3 * sizeof(WCHAR);
+++    DriveLetter->Buffer = AllocatePool(sizeof(DosDevices.Buffer) + 3 * sizeof(WCHAR));
+++    if (!DriveLetter->Buffer)
+++    {
+++        return STATUS_INSUFFICIENT_RESOURCES;
+++    }
+++
+++    /* Copy prefix */
+++    RtlCopyUnicodeString(DriveLetter, &DosDevices);
+++
+++    /* Update string to reflect real contents */
+++    DriveLetter->Length = sizeof(DosDevices.Buffer) + 2 * sizeof(WCHAR);
+++    DriveLetter->Buffer[(sizeof(DosDevices.Buffer) + 2 * sizeof(WCHAR)) / sizeof (WCHAR)] = UNICODE_NULL;
+++    DriveLetter->Buffer[(sizeof(DosDevices.Buffer) + sizeof(WCHAR)) / sizeof (WCHAR)] = L':';
+++
+++    /* If caller wants a no drive entry */
+++    if (Letter == (UCHAR)-1)
+++    {
+++        /* Then, create a no letter entry */
+++        CreateNoDriveLetterEntry(UniqueId);
+++        FreePool(DriveLetter->Buffer);
+++        return STATUS_UNSUCCESSFUL;
+++    }
+++    else if (Letter)
+++    {
+++        /* Use the letter given by the caller */
+++        DriveLetter->Buffer[sizeof(DosDevices.Buffer) / sizeof(WCHAR)] = (WCHAR)Letter;
+++        Status = GlobalCreateSymbolicLink(DriveLetter, DeviceName);
+++        if (NT_SUCCESS(Status))
+++        {
+++            return Status;
+++        }
+++    }
+++
+++    /* If caller didn't provide a letter, let's find one for him.
+++     * If device is a floppy, start with letter A
+++     */
+++    if (RtlPrefixUnicodeString(&DeviceFloppy, DeviceName, TRUE))
+++    {
+++        Letter = 'A';
+++    }
+++    else
+++    {
+++        /* Otherwise, if device is a cd rom, then, start with D.
+++         * Finally, if a disk, use C
+++         */
+++        Letter = RtlPrefixUnicodeString(&DeviceCdRom, DeviceName, TRUE) + 'C';
+++    }
+++
+++    /* Try to affect a letter (up to Z, ofc) until it's possible */
+++    for (; Letter <= 'Z'; Letter++)
+++    {
+++        DriveLetter->Buffer[sizeof(DosDevices.Buffer) / sizeof(WCHAR)] = (WCHAR)Letter;
+++        Status = GlobalCreateSymbolicLink(DriveLetter, DeviceName);
+++        if (NT_SUCCESS(Status))
+++        {
+++            return Status;
+++        }
+++    }
+++
+++    /* We failed to allocate a letter */
+++    FreePool(DriveLetter->Buffer);
+++    return Status;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++NTSTATUS
+++QueryDeviceInformation(IN PUNICODE_STRING SymbolicName,
+++                       OUT PUNICODE_STRING DeviceName OPTIONAL,
+++                       OUT PMOUNTDEV_UNIQUE_ID * UniqueId OPTIONAL,
+++                       OUT PBOOLEAN Removable OPTIONAL,
+++                       OUT PBOOLEAN GptDriveLetter OPTIONAL,
+++                       OUT PBOOLEAN HasGuid OPTIONAL,
+++                       IN OUT LPGUID StableGuid OPTIONAL,
+++                       OUT PBOOLEAN Valid OPTIONAL)
+++{
+++    PIRP Irp;
+++    USHORT Size;
+++    KEVENT Event;
+++    NTSTATUS Status;
+++    BOOLEAN IsRemovable;
+++    PMOUNTDEV_NAME Name;
+++    PMOUNTDEV_UNIQUE_ID Id;
+++    PFILE_OBJECT FileObject;
+++    PIO_STACK_LOCATION Stack;
+++    PDEVICE_OBJECT DeviceObject;
+++    IO_STATUS_BLOCK IoStatusBlock;
+++    PARTITION_INFORMATION_EX PartitionInfo;
+++    STORAGE_DEVICE_NUMBER StorageDeviceNumber;
+++    VOLUME_GET_GPT_ATTRIBUTES_INFORMATION GptAttributes;
+++
+++    /* Get device associated with the symbolic name */
+++    Status = IoGetDeviceObjectPointer(SymbolicName,
+++                                      FILE_READ_ATTRIBUTES,
+++                                      &FileObject,
+++                                      &DeviceObject);
+++    if (!NT_SUCCESS(Status))
+++    {
+++        return Status;
+++    }
+++
+++    /* The associate FO can't have a file name */
+++    if (FileObject->FileName.Length)
+++    {
+++        ObfDereferenceObject(FileObject);
+++        return STATUS_OBJECT_NAME_NOT_FOUND;
+++    }
+++
+++    /* Check if it's removable & return to the user (if asked to) */
+++    IsRemovable = (FileObject->DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA);
+++    if (Removable)
+++    {
+++        *Removable = IsRemovable;
+++    }
+++
+++    /* Get the attached device */
+++    DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
+++
+++    /* If we've been asked for a GPT drive letter */
+++    if (GptDriveLetter)
+++    {
+++        /* Consider it has one */
+++        *GptDriveLetter = TRUE;
+++
+++        if (!IsRemovable)
+++        {
+++            /* Query the GPT attributes */
+++            KeInitializeEvent(&Event, NotificationEvent, FALSE);
+++            Irp = IoBuildDeviceIoControlRequest(IOCTL_VOLUME_GET_GPT_ATTRIBUTES,
+++                                                DeviceObject,
+++                                                NULL,
+++                                                0,
+++                                                &GptAttributes,
+++                                                sizeof(GptAttributes),
+++                                                FALSE,
+++                                                &Event,
+++                                                &IoStatusBlock);
+++            if (!Irp)
+++            {
+++                ObfDereferenceObject(DeviceObject);
+++                ObfDereferenceObject(FileObject);
+++                return STATUS_INSUFFICIENT_RESOURCES;
+++            }
+++
+++            Status = IofCallDriver(DeviceObject, Irp);
+++            if (Status == STATUS_PENDING)
+++            {
+++                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+++                Status =  IoStatusBlock.Status;
+++            }
+++
+++            /* In case of failure, don't fail, that's no vital */
+++            if (!NT_SUCCESS(Status))
+++            {
+++                Status = STATUS_SUCCESS;
+++            }
+++            /* Check if it has a drive letter */
+++            else if (!(GptAttributes.GptAttributes &
+++                       GPT_BASIC_DATA_ATTRIBUTE_NO_DRIVE_LETTER))
+++            {
+++                *GptDriveLetter = FALSE;
+++            }
+++        }
+++    }
+++
+++    /* If caller wants to know if there's valid contents */
+++    if (Valid)
+++    {
+++        /* Suppose it's not OK */
+++        *Valid = FALSE;
+++
+++        if (!IsRemovable)
+++        {
+++            /* Query partitions information */
+++            KeInitializeEvent(&Event, NotificationEvent, FALSE);
+++            Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
+++                                                DeviceObject,
+++                                                NULL,
+++                                                0,
+++                                                &PartitionInfo,
+++                                                sizeof(PartitionInfo),
+++                                                FALSE,
+++                                                &Event,
+++                                                &IoStatusBlock);
+++            if (!Irp)
+++            {
+++                ObfDereferenceObject(DeviceObject);
+++                ObfDereferenceObject(FileObject);
+++                return STATUS_INSUFFICIENT_RESOURCES;
+++            }
+++
+++            Status = IofCallDriver(DeviceObject, Irp);
+++            if (Status == STATUS_PENDING)
+++            {
+++                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+++                Status =  IoStatusBlock.Status;
+++            }
+++
+++            /* Once again here, failure isn't major */
+++            if (!NT_SUCCESS(Status))
+++            {
+++                Status = STATUS_SUCCESS;
+++            }
+++            /* Verify we know something in */
+++            else if (PartitionInfo.PartitionStyle == PARTITION_STYLE_MBR &&
+++                     IsRecognizedPartition(PartitionInfo.Mbr.PartitionType))
+++            {
+++                *Valid = TRUE;
+++            }
+++
+++            /* It looks correct, ensure it is & query device number */
+++            if (*Valid)
+++            {
+++                KeInitializeEvent(&Event, NotificationEvent, FALSE);
+++                Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
+++                                                    DeviceObject,
+++                                                    NULL,
+++                                                    0,
+++                                                    &StorageDeviceNumber,
+++                                                    sizeof(StorageDeviceNumber),
+++                                                    FALSE,
+++                                                    &Event,
+++                                                    &IoStatusBlock);
+++                if (!Irp)
+++                {
+++                    ObfDereferenceObject(DeviceObject);
+++                    ObfDereferenceObject(FileObject);
+++                    return STATUS_INSUFFICIENT_RESOURCES;
+++                }
+++
+++                Status = IofCallDriver(DeviceObject, Irp);
+++                if (Status == STATUS_PENDING)
+++                {
+++                    KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+++                    Status =  IoStatusBlock.Status;
+++                }
+++
+++                if (!NT_SUCCESS(Status))
+++                {
+++                    Status = STATUS_SUCCESS;
+++                }
+++                else
+++                {
+++                    *Valid = FALSE;
+++                }
+++            }
+++        }
+++    }
+++
+++    /* If caller needs device name */
+++    if (DeviceName)
+++    {
+++        /* Allocate a buffer just to request length */
+++        Name = AllocatePool(sizeof(MOUNTDEV_NAME));
+++        if (!Name)
+++        {
+++            ObfDereferenceObject(DeviceObject);
+++            ObfDereferenceObject(FileObject);
+++            return STATUS_INSUFFICIENT_RESOURCES;
+++        }
+++
+++        /* Query device name */
+++        KeInitializeEvent(&Event, NotificationEvent, FALSE);
+++        Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
+++                                            DeviceObject,
+++                                            NULL,
+++                                            0,
+++                                            Name,
+++                                            sizeof(MOUNTDEV_NAME),
+++                                            FALSE,
+++                                            &Event,
+++                                            &IoStatusBlock);
+++        if (!Irp)
+++        {
+++            FreePool(Name);
+++            ObDereferenceObject(DeviceObject);
+++            ObDereferenceObject(FileObject);
+++            return STATUS_INSUFFICIENT_RESOURCES;
+++        }
+++
+++        Stack = IoGetNextIrpStackLocation(Irp);
+++        Stack->FileObject = FileObject;
+++
+++        Status = IofCallDriver(DeviceObject, Irp);
+++        if (Status == STATUS_PENDING)
+++        {
+++            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+++            Status = IoStatusBlock.Status;
+++        }
+++
+++        /* Now, we've got the correct length */
+++        if (Status == STATUS_BUFFER_OVERFLOW)
+++        {
+++            Size = Name->NameLength + sizeof(MOUNTDEV_NAME);
+++
+++            FreePool(Name);
+++
+++            /* Allocate proper size */
+++            Name = AllocatePool(Size);
+++            if (!Name)
+++            {
+++                ObfDereferenceObject(DeviceObject);
+++                ObfDereferenceObject(FileObject);
+++                return STATUS_INSUFFICIENT_RESOURCES;
+++            }
+++
+++            /* And query name (for real that time) */
+++            KeInitializeEvent(&Event, NotificationEvent, FALSE);
+++            Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
+++                                                DeviceObject,
+++                                                NULL,
+++                                                0,
+++                                                Name,
+++                                                Size,
+++                                                FALSE,
+++                                                &Event,
+++                                                &IoStatusBlock);
+++            if (!Irp)
+++            {
+++                FreePool(Name);
+++                ObDereferenceObject(DeviceObject);
+++                ObDereferenceObject(FileObject);
+++                return STATUS_INSUFFICIENT_RESOURCES;
+++            }
+++
+++            Stack = IoGetNextIrpStackLocation(Irp);
+++            Stack->FileObject = FileObject;
+++
+++            Status = IofCallDriver(DeviceObject, Irp);
+++            if (Status == STATUS_PENDING)
+++            {
+++                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+++                Status = IoStatusBlock.Status;
+++            }
+++        }
+++
+++        /* Here we can't fail and assume default value */
+++        if (!NT_SUCCESS(Status))
+++        {
+++            FreePool(Name);
+++            ObDereferenceObject(DeviceObject);
+++            ObDereferenceObject(FileObject);
+++            return Status;
+++        }
+++
+++        /* Copy back found name to the caller */
+++        DeviceName->Length = Name->NameLength;
+++        DeviceName->MaximumLength = Name->NameLength + sizeof(WCHAR);
+++        DeviceName->Buffer = AllocatePool(DeviceName->MaximumLength);
+++        if (!DeviceName->Buffer)
+++        {
+++            FreePool(Name);
+++            ObDereferenceObject(DeviceObject);
+++            ObDereferenceObject(FileObject);
+++            return STATUS_INSUFFICIENT_RESOURCES;
+++        }
+++
+++        RtlCopyMemory(DeviceName->Buffer, Name->Name, Name->NameLength);
+++        DeviceName->Buffer[Name->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
+++        FreePool(Name);
+++    }
+++
+++    /* If caller wants device unique ID */
+++    if (UniqueId)
+++    {
+++        /* Prepare buffer to probe length */
+++        Id = AllocatePool(sizeof(MOUNTDEV_UNIQUE_ID));
+++        if (!Id)
+++        {
+++            ObDereferenceObject(DeviceObject);
+++            ObDereferenceObject(FileObject);
+++            return STATUS_INSUFFICIENT_RESOURCES;
+++        }
+++
+++        /* Query unique ID length */
+++        KeInitializeEvent(&Event, NotificationEvent, FALSE);
+++        Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_UNIQUE_ID,
+++                                            DeviceObject,
+++                                            NULL,
+++                                            0,
+++                                            Id,
+++                                            sizeof(MOUNTDEV_UNIQUE_ID),
+++                                            FALSE,
+++                                            &Event,
+++                                            &IoStatusBlock);
+++        if (!Irp)
+++        {
+++            FreePool(Id);
+++            ObfDereferenceObject(DeviceObject);
+++            ObfDereferenceObject(FileObject);
+++            return STATUS_INSUFFICIENT_RESOURCES;
+++        }
+++
+++        Stack = IoGetNextIrpStackLocation(Irp);
+++        Stack->FileObject = FileObject;
+++
+++        Status = IofCallDriver(DeviceObject, Irp);
+++        if (Status == STATUS_PENDING)
+++        {
+++            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+++            Status = IoStatusBlock.Status;
+++        }
+++
+++        /* Retry with appropriate length */
+++        if (Status == STATUS_BUFFER_OVERFLOW)
+++        {
+++            Size = Id->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID);
+++
+++            FreePool(Id);
+++
+++            /* Allocate the correct buffer */
+++            Id = AllocatePool(Size);
+++            if (!Id)
+++            {
+++                ObfDereferenceObject(DeviceObject);
+++                ObfDereferenceObject(FileObject);
+++                return STATUS_INSUFFICIENT_RESOURCES;
+++            }
+++
+++            /* Query unique ID */
+++            KeInitializeEvent(&Event, NotificationEvent, FALSE);
+++            Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
+++                                                DeviceObject,
+++                                                NULL,
+++                                                0,
+++                                                Id,
+++                                                Size,
+++                                                FALSE,
+++                                                &Event,
+++                                                &IoStatusBlock);
+++            if (!Irp)
+++            {
+++                FreePool(Id);
+++                ObDereferenceObject(DeviceObject);
+++                ObDereferenceObject(FileObject);
+++                return STATUS_INSUFFICIENT_RESOURCES;
+++            }
+++
+++            Stack = IoGetNextIrpStackLocation(Irp);
+++            Stack->FileObject = FileObject;
+++
+++            Status = IofCallDriver(DeviceObject, Irp);
+++            if (Status == STATUS_PENDING)
+++            {
+++                KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+++                Status = IoStatusBlock.Status;
+++            }
+++        }
+++
+++        /* Hands back unique ID */
+++        if (NT_SUCCESS(Status))
+++        {
+++            *UniqueId = Id;
+++        }
+++        else
+++        {
+++            /* In case of failure, also free the rest */
+++            FreePool(Id);
+++            if (DeviceName->Length)
+++            {
+++                FreePool(DeviceName->Buffer);
+++            }
+++
+++            ObDereferenceObject(DeviceObject);
+++            ObDereferenceObject(FileObject);
+++
+++            return Status;
+++        }
+++    }
+++
+++    /* If user wants to know about GUID */
+++    if (HasGuid)
+++    {
+++        /* Query device stable GUID */
+++        KeInitializeEvent(&Event, NotificationEvent, FALSE);
+++        Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_STABLE_GUID,
+++                                            DeviceObject,
+++                                            NULL,
+++                                            0,
+++                                            StableGuid,
+++                                            sizeof(GUID),
+++                                            FALSE,
+++                                            &Event,
+++                                            &IoStatusBlock);
+++        if (!Irp)
+++        {
+++            ObfDereferenceObject(DeviceObject);
+++            ObfDereferenceObject(FileObject);
+++            return STATUS_INSUFFICIENT_RESOURCES;
+++        }
+++
+++        Stack = IoGetNextIrpStackLocation(Irp);
+++        Stack->FileObject = FileObject;
+++
+++        Status = IofCallDriver(DeviceObject, Irp);
+++        if (Status == STATUS_PENDING)
+++        {
+++            KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
+++            Status = IoStatusBlock.Status;
+++        }
+++
+++        *HasGuid = NT_SUCCESS(Status);
+++    }
+++
+++    ObfDereferenceObject(DeviceObject);
+++    ObfDereferenceObject(FileObject);
+++    return Status;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++NTSTATUS
+++FindDeviceInfo(IN PDEVICE_EXTENSION DeviceExtension,
+++               IN PUNICODE_STRING SymbolicName,
+++               IN BOOLEAN DeviceNameGiven,
+++               OUT PDEVICE_INFORMATION * DeviceInformation)
+++{
+++    NTSTATUS Status;
+++    PLIST_ENTRY NextEntry;
+++    UNICODE_STRING DeviceName;
+++    PDEVICE_INFORMATION DeviceInfo = NULL;
+++
+++    /* If a device name was given, use it */
+++    if (DeviceNameGiven)
+++    {
+++        DeviceName.Length = SymbolicName->Length;
+++        DeviceName.Buffer = SymbolicName->Buffer;
+++    }
+++    else
+++    {
+++        /* Otherwise, query it */
+++        Status = QueryDeviceInformation(SymbolicName,
+++                                        &DeviceName,
+++                                        NULL, NULL,
+++                                        NULL, NULL,
+++                                        NULL, NULL);
+++        if (!NT_SUCCESS(Status))
+++        {
+++            return Status;
+++        }
+++    }
+++
+++    /* Look for device information matching devive */
+++    for (NextEntry = DeviceExtension->DeviceListHead.Flink;
+++         NextEntry != &(DeviceExtension->DeviceListHead);
+++         NextEntry = NextEntry->Flink)
+++    {
+++        DeviceInfo = CONTAINING_RECORD(NextEntry,
+++                                       DEVICE_INFORMATION,
+++                                       DeviceListEntry);
+++
+++        if (RtlEqualUnicodeString(&DeviceName, &(DeviceInfo->DeviceName), TRUE))
+++        {
+++            break;
+++        }
+++    }
+++
+++    /* Release our buffer if required */
+++    if (!DeviceNameGiven)
+++    {
+++        FreePool(DeviceName.Buffer);
+++    }
+++
+++    /* Return found intormation */
+++    if (NextEntry == &(DeviceExtension->DeviceListHead))
+++    {
+++        return STATUS_OBJECT_NAME_NOT_FOUND;
+++    }
+++
+++    *DeviceInformation = DeviceInfo;
+++    return STATUS_SUCCESS;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++VOID
+++MountMgrFreeDeadDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation)
+++{
+++    FreePool(DeviceInformation->SymbolicName.Buffer);
+++    FreePool(DeviceInformation);
+++}
+++
+++/*
+++ * @implemented
+++ */
+++VOID
+++MountMgrFreeMountedDeviceInfo(IN PDEVICE_INFORMATION DeviceInformation)
+++{
+++    PLIST_ENTRY NextEntry;
+++    PSYMLINK_INFORMATION SymLink;
+++    PUNIQUE_ID_REPLICATE UniqueId;
+++    PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
+++
+++    /* Purge symbolic links list */
+++    while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
+++    {
+++        NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead));
+++        SymLink = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+++
+++        GlobalDeleteSymbolicLink(&(SymLink->Name));
+++        FreePool(SymLink->Name.Buffer);
+++    }
+++
+++    /* Purge replicated unique IDs list */
+++    while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead)))
+++    {
+++        NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead));
+++        UniqueId = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
+++
+++        FreePool(UniqueId->UniqueId);
+++        FreePool(UniqueId);
+++    }
+++
+++    while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead)))
+++    {
+++        NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead));
+++        AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
+++
+++        FreePool(AssociatedDevice->String.Buffer);
+++        FreePool(AssociatedDevice);
+++    }
+++
+++    /* Free the rest of the buffers */
+++    FreePool(DeviceInformation->SymbolicName.Buffer);
+++    if (DeviceInformation->KeepLinks)
+++    {
+++        FreePool(DeviceInformation->UniqueId);
+++    }
+++    FreePool(DeviceInformation->DeviceName.Buffer);
+++
+++    /* Finally, stop waiting for notifications for this device */
+++    if (DeviceInformation->TargetDeviceNotificationEntry)
+++    {
+++        IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry);
+++    }
+++}
+++
+++/*
+++ * @implemented
+++ */
+++VOID
+++MountMgrFreeSavedLink(IN PSAVED_LINK_INFORMATION SavedLinkInformation)
+++{
+++    PLIST_ENTRY NextEntry;
+++    PSYMLINK_INFORMATION SymlinkInformation;
+++
+++    /* For all the saved links */
+++    while (!IsListEmpty(&(SavedLinkInformation->SymbolicLinksListHead)))
+++    {
+++        NextEntry = RemoveHeadList(&(SavedLinkInformation->SymbolicLinksListHead));
+++        SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+++
+++        /* Remove from system & free */
+++        GlobalDeleteSymbolicLink(&(SymlinkInformation->Name));
+++        FreePool(SymlinkInformation->Name.Buffer);
+++        FreePool(SymlinkInformation);
+++    }
+++
+++    /* And free unique ID & entry */
+++    FreePool(SavedLinkInformation->UniqueId);
+++    FreePool(SavedLinkInformation);
+++}
+++
+++
+++/*
+++ * @implemented
+++ */
+++VOID
+++NTAPI
+++MountMgrUnload(IN struct _DRIVER_OBJECT *DriverObject)
+++{
+++    PLIST_ENTRY NextEntry;
+++    PUNIQUE_ID_WORK_ITEM WorkItem;
+++    PDEVICE_EXTENSION DeviceExtension;
+++    PDEVICE_INFORMATION DeviceInformation;
+++    PSAVED_LINK_INFORMATION SavedLinkInformation;
+++
+++    /* Don't get notification any longer */
+++    IoUnregisterShutdownNotification(gdeviceObject);
+++
+++    /* Free registry buffer */
+++    DeviceExtension = gdeviceObject->DeviceExtension;
+++    if (DeviceExtension->RegistryPath.Buffer)
+++    {
+++        FreePool(DeviceExtension->RegistryPath.Buffer);
+++        DeviceExtension->RegistryPath.Buffer = NULL;
+++    }
+++
+++    InterlockedExchange(&Unloading, TRUE);
+++
+++    KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE);
+++
+++    /* Wait for workers to finish */
+++    if (InterlockedIncrement(&DeviceExtension->WorkerReferences))
+++    {
+++        KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore),
+++                           IO_NO_INCREMENT, 1, FALSE);
+++
+++        KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
+++    }
+++    else
+++    {
+++        InterlockedDecrement(&(DeviceExtension->WorkerReferences));
+++    }
+++
+++    /* Don't get any notification any longer² */
+++    IoUnregisterPlugPlayNotification(DeviceExtension->NotificationEntry);
+++
+++    /* Acquire the driver exclusively */
+++    KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode,
+++                          FALSE, NULL);
+++
+++    /* Clear offline devices list */
+++    while (!IsListEmpty(&(DeviceExtension->OfflineDeviceListHead)))
+++    {
+++        NextEntry = RemoveHeadList(&(DeviceExtension->OfflineDeviceListHead));
+++        DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
+++        MountMgrFreeDeadDeviceInfo(DeviceInformation);
+++    }
+++
+++    /* Clear saved links list */
+++    while (!IsListEmpty(&(DeviceExtension->SavedLinksListHead)))
+++    {
+++        NextEntry = RemoveHeadList(&(DeviceExtension->SavedLinksListHead));
+++        SavedLinkInformation = CONTAINING_RECORD(NextEntry, SAVED_LINK_INFORMATION, SavedLinksListEntry);
+++        MountMgrFreeSavedLink(SavedLinkInformation);
+++    }
+++
+++    /* Clear workers list */
+++    while (!IsListEmpty(&(DeviceExtension->UniqueIdWorkerItemListHead)))
+++    {
+++        NextEntry = RemoveHeadList(&(DeviceExtension->UniqueIdWorkerItemListHead));
+++        WorkItem = CONTAINING_RECORD(NextEntry, UNIQUE_ID_WORK_ITEM, UniqueIdWorkerItemListEntry);
+++
+++        KeResetEvent(&UnloadEvent);
+++        WorkItem->Event = &UnloadEvent;
+++
+++        KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT,
+++                           1, FALSE);
+++
+++        IoCancelIrp(WorkItem->Irp);
+++        KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
+++
+++        IoFreeIrp(WorkItem->Irp);
+++        FreePool(WorkItem->DeviceName.Buffer);
+++        FreePool(WorkItem->IrpBuffer);
+++        FreePool(WorkItem);
+++
+++        KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode,
+++                              FALSE, NULL);
+++    }
+++
+++    /* If we have drive letter data, release */
+++    if (DeviceExtension->DriveLetterData)
+++    {
+++        FreePool(DeviceExtension->DriveLetterData);
+++        DeviceExtension->DriveLetterData = NULL;
+++    }
+++
+++    /* Release driver & quit */
+++    KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
+++
+++    GlobalDeleteSymbolicLink(&DosDevicesMount);
+++    IoDeleteDevice(gdeviceObject);
+++}
+++
+++/*
+++ * @implemented
+++ */
+++ULONG
+++MountmgrReadNoAutoMount(IN PUNICODE_STRING RegistryPath)
+++{
+++    NTSTATUS Status;
+++    ULONG Result, Default = 0;
+++    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+++
+++    RtlZeroMemory(QueryTable, sizeof(QueryTable));
+++
+++    /* Simply read data from register */
+++    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
+++    QueryTable[0].Name = L"NoAutoMount";
+++    QueryTable[0].EntryContext = &Result;
+++    QueryTable[0].DefaultType = REG_NONE;
+++    QueryTable[0].DefaultData = &Default;
+++    QueryTable[0].DefaultLength = sizeof(ULONG);
+++
+++    Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
+++                                    RegistryPath->Buffer,
+++                                    QueryTable,
+++                                    NULL,
+++                                    NULL);
+++    if (!NT_SUCCESS(Status))
+++    {
+++        return Default;
+++    }
+++
+++    return Result;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++NTSTATUS
+++MountMgrMountedDeviceArrival(IN PDEVICE_EXTENSION DeviceExtension,
+++                             IN PUNICODE_STRING SymbolicName,
+++                             IN BOOLEAN FromVolume)
+++{
+++    WCHAR Letter;
+++    GUID StableGuid;
+++    HANDLE LinkHandle;
+++    ULONG SymLinkCount, i;
+++    PLIST_ENTRY NextEntry;
+++    PUNICODE_STRING SymLinks;
+++    NTSTATUS Status, IntStatus;
+++    OBJECT_ATTRIBUTES ObjectAttributes;
+++    PSYMLINK_INFORMATION SymlinkInformation;
+++    PMOUNTDEV_UNIQUE_ID UniqueId, NewUniqueId;
+++    PSAVED_LINK_INFORMATION SavedLinkInformation;
+++    PDEVICE_INFORMATION DeviceInformation, CurrentDevice;
+++    WCHAR CSymLinkBuffer[MAX_PATH], LinkTargetBuffer[MAX_PATH];
+++    UNICODE_STRING TargetDeviceName, SuggestedLinkName, DeviceName, VolumeName, DriveLetter, LinkTarget, CSymLink;
+++    BOOLEAN HasGuid, HasGptDriveLetter, Valid, UseOnlyIfThereAreNoOtherLinks, IsDrvLetter, IsOff, IsVolumeName, LinkError;
+++
+++    /* New device = new structure to represent it */
+++    DeviceInformation = AllocatePool(sizeof(DEVICE_INFORMATION));
+++    if (!DeviceInformation)
+++    {
+++        return STATUS_INSUFFICIENT_RESOURCES;
+++    }
+++
+++    /* Initialise device structure */
+++    RtlZeroMemory(DeviceInformation, sizeof(DEVICE_INFORMATION));
+++    InitializeListHead(&(DeviceInformation->SymbolicLinksListHead));
+++    InitializeListHead(&(DeviceInformation->ReplicatedUniqueIdsListHead));
+++    InitializeListHead(&(DeviceInformation->AssociatedDevicesHead));
+++    DeviceInformation->SymbolicName.Length = SymbolicName->Length;
+++    DeviceInformation->SymbolicName.MaximumLength = SymbolicName->Length + sizeof(UNICODE_NULL);
+++    DeviceInformation->SymbolicName.Buffer = AllocatePool(DeviceInformation->SymbolicName.MaximumLength);
+++    if (!DeviceInformation->SymbolicName.Buffer)
+++    {
+++        FreePool(DeviceInformation);
+++        return STATUS_INSUFFICIENT_RESOURCES;
+++    }
+++
+++    /* Copy symbolic name */
+++    RtlCopyMemory(DeviceInformation->SymbolicName.Buffer, SymbolicName->Buffer, SymbolicName->Length);
+++    DeviceInformation->SymbolicName.Buffer[DeviceInformation->SymbolicName.Length / sizeof(WCHAR)] = UNICODE_NULL;
+++    DeviceInformation->Volume = FromVolume;
+++    DeviceInformation->DeviceExtension = DeviceExtension;
+++
+++    /* Query as much data as possible about device */
+++    Status = QueryDeviceInformation(SymbolicName,
+++                                    &TargetDeviceName,
+++                                    &UniqueId,
+++                                    &(DeviceInformation->Removable),
+++                                    &HasGptDriveLetter,
+++                                    &HasGuid,
+++                                    &StableGuid,
+++                                    &Valid);
+++    if (!NT_SUCCESS(Status))
+++    {
+++        KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
+++
+++        for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink;
+++             NextEntry != &(DeviceExtension->OfflineDeviceListHead);
+++             NextEntry = NextEntry->Flink)
+++        {
+++            CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
+++
+++            if (RtlEqualUnicodeString(&(DeviceInformation->SymbolicName), &(CurrentDevice->SymbolicName), TRUE))
+++            {
+++                break;            
+++            }
+++        }
+++
+++        if (NextEntry != &(DeviceExtension->OfflineDeviceListHead))
+++        {
+++            MountMgrFreeDeadDeviceInfo(DeviceInformation);
+++        }
+++        else
+++        {
+++            InsertTailList(&(DeviceExtension->OfflineDeviceListHead), &(DeviceInformation->DeviceListEntry));
+++        }
+++
+++        KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
+++
+++        return Status;
+++    }
+++
+++    /* Save gathered data */
+++    DeviceInformation->UniqueId = UniqueId;
+++    DeviceInformation->DeviceName = TargetDeviceName;
+++    DeviceInformation->KeepLinks = FALSE;
+++
+++    /* If we found system partition, mark it */
+++    if (DeviceExtension->DriveLetterData && UniqueId->UniqueIdLength == DeviceExtension->DriveLetterData->UniqueIdLength)
+++    {
+++        if (RtlCompareMemory(UniqueId->UniqueId, DeviceExtension->DriveLetterData->UniqueId, UniqueId->UniqueIdLength)
+++            == UniqueId->UniqueIdLength)
+++        {
+++            IoSetSystemPartition(&TargetDeviceName);
+++        }
+++    }
+++
+++    /* Check suggested link name */
+++    Status = QuerySuggestedLinkName(&(DeviceInformation->SymbolicName),
+++                                    &SuggestedLinkName,
+++                                    &UseOnlyIfThereAreNoOtherLinks);
+++    if (!NT_SUCCESS(Status))
+++    {
+++        SuggestedLinkName.Buffer = NULL;
+++    }
+++
+++    /* If it's OK, set it and save its letter (if any) */
+++    if (SuggestedLinkName.Buffer && IsDriveLetter(&SuggestedLinkName))
+++    {
+++        DeviceInformation->SuggestedDriveLetter = SuggestedLinkName.Buffer[LETTER_POSITION];
+++    }
+++
+++    /* Acquire driver exclusively */
+++    KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
+++
+++    /* Check if we already have device in to prevent double registration */
+++    for (NextEntry = DeviceExtension->DeviceListHead.Flink;
+++         NextEntry != &(DeviceExtension->DeviceListHead);
+++         NextEntry = NextEntry->Flink)
+++    {
+++        CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
+++
+++        if (RtlEqualUnicodeString(&(DeviceInformation->DeviceName), &TargetDeviceName, TRUE))
+++        {
+++            break;            
+++        }
+++    }
+++
+++    /* If we found it, clear ours, and return success, all correct */
+++    if (NextEntry != &(DeviceExtension->DeviceListHead))
+++    {
+++        if (SuggestedLinkName.Buffer)
+++        {
+++            FreePool(SuggestedLinkName.Buffer);
+++        }
+++
+++        FreePool(UniqueId);
+++        FreePool(TargetDeviceName.Buffer);
+++        FreePool(DeviceInformation->DeviceName.Buffer);
+++        FreePool(DeviceInformation);
+++
+++        KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
+++
+++        return STATUS_SUCCESS;
+++    }
+++
+++    /* Check if there are symlinks associated with our device in registry */
+++    Status = QuerySymbolicLinkNamesFromStorage(DeviceExtension,
+++                                               DeviceInformation,
+++                                               (SuggestedLinkName.Buffer) ? &SuggestedLinkName : NULL,
+++                                               UseOnlyIfThereAreNoOtherLinks,
+++                                               &SymLinks,
+++                                               &SymLinkCount,
+++                                               HasGuid,
+++                                               &StableGuid);
+++
+++    /* If our device is a CD-ROM */
+++    if (RtlPrefixUnicodeString(&DeviceCdRom, &TargetDeviceName, TRUE))
+++    {
+++        LinkTarget.Length = 0;
+++        LinkTarget.MaximumLength = sizeof(LinkTargetBuffer);
+++        LinkTarget.Buffer = LinkTargetBuffer;
+++
+++        RtlCopyMemory(CSymLinkBuffer, Cunc, sizeof(Cunc));
+++        RtlInitUnicodeString(&CSymLink, CSymLinkBuffer);
+++
+++        /* Start checking all letters that could have been associated */
+++        for (Letter = L'D'; Letter <= L'Z'; Letter++)
+++        {
+++            CSymLink.Buffer[LETTER_POSITION] = Letter;
+++
+++            InitializeObjectAttributes(&ObjectAttributes,
+++                                       &CSymLink,
+++                                       OBJ_CASE_INSENSITIVE,
+++                                       NULL,
+++                                       NULL);
+++
+++            /* Try to open the associated symlink */
+++            Status = ZwOpenSymbolicLinkObject(&LinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
+++            if (!NT_SUCCESS(Status))
+++            {
+++                continue;
+++            }
+++
+++            /* And query its target */
+++            Status = ZwQuerySymbolicLinkObject(LinkHandle, &LinkTarget, NULL);
+++            ZwClose(LinkHandle);
+++
+++            if (!NT_SUCCESS(Status))
+++            {
+++                continue;
+++            }
+++
+++            IntStatus = STATUS_UNSUCCESSFUL;
+++            if (!RtlEqualUnicodeString(&LinkTarget, &DeviceInformation->DeviceName, FALSE))
+++            {
+++                continue;
+++            }
+++
+++            /* This link is matching our device, whereas it's not supposed to have any
+++             * symlink associated.
+++             * Delete it
+++             */
+++            if (!SymLinkCount)
+++            {
+++                IoDeleteSymbolicLink(&CSymLink);
+++                continue;
+++            }
+++
+++            /* Now, for all the symlinks, check for ours */
+++            for (i = 0; i < SymLinkCount; i++)
+++            {
+++                if (IsDriveLetter(&(SymLinks[i])))
+++                {
+++                    /* If it exists, that's correct */
+++                    if (SymLinks[i].Buffer[LETTER_POSITION] == Letter)
+++                    {
+++                        IntStatus = STATUS_SUCCESS;
+++                    }
+++                }
+++            }
+++
+++            /* Useless link, delete it */
+++            if (IntStatus == STATUS_UNSUCCESSFUL)
+++            {
+++                IoDeleteSymbolicLink(&CSymLink);
+++            }
+++        }
+++    }
+++
+++    /* Suggested name is no longer required */
+++    if (SuggestedLinkName.Buffer)
+++    {
+++        FreePool(SuggestedLinkName.Buffer);
+++    }
+++
+++    /* If if failed, ensure we don't take symlinks into account */
+++    if (!NT_SUCCESS(Status))
+++    {
+++        SymLinks = NULL;
+++        SymLinkCount = 0;
+++    }
+++
+++    /* Now we queried them, remove the symlinks */
+++    SavedLinkInformation = RemoveSavedLinks(DeviceExtension, UniqueId);
+++
+++    IsDrvLetter = FALSE;
+++    IsOff = FALSE;
+++    IsVolumeName = FALSE;
+++    /* For all the symlinks */
+++    for (i = 0; i < SymLinkCount; i++)
+++    {
+++        /* Check if our device is a volume */
+++        if (MOUNTMGR_IS_VOLUME_NAME(&(SymLinks[i])))
+++        {
+++            IsVolumeName = TRUE;
+++        }
+++        /* If it has a drive letter */
+++        else if (IsDriveLetter(&(SymLinks[i])))
+++        {
+++            if (IsDrvLetter)
+++            {
+++                DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId);
+++                continue;
+++            }
+++            else
+++            {
+++                IsDrvLetter = TRUE;
+++            }
+++        }
+++
+++        /* And recreate the symlink to our device */
+++        Status = GlobalCreateSymbolicLink(&(SymLinks[i]), &TargetDeviceName);
+++        if (!NT_SUCCESS(Status))
+++        {
+++            LinkError = TRUE;
+++
+++            if ((SavedLinkInformation && !RedirectSavedLink(SavedLinkInformation, &(SymLinks[i]), &TargetDeviceName)) ||
+++                !SavedLinkInformation)
+++            {
+++                Status = QueryDeviceInformation(&(SymLinks[i]), &DeviceName, NULL, NULL, NULL, NULL, NULL, NULL);
+++                if (NT_SUCCESS(Status))
+++                {
+++                    LinkError = RtlEqualUnicodeString(&TargetDeviceName, &DeviceName, TRUE);
+++                    FreePool(DeviceName.Buffer);
+++                }
+++
+++                if (!LinkError)
+++                {
+++                    if (IsDriveLetter(&(SymLinks[i])))
+++                    {
+++                        IsDrvLetter = FALSE;
+++                        DeleteFromLocalDatabase(&(SymLinks[i]), UniqueId);
+++                    }
+++
+++                    FreePool(SymLinks[i].Buffer);
+++                    continue;
+++                }
+++            }
+++        }
+++
+++        /* Check if was offline */
+++        if (IsOffline(&(SymLinks[i])))
+++        {
+++            IsOff = TRUE;
+++        }
+++
+++        /* Finally, associate this symlink with the device */
+++        SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
+++        if (!SymlinkInformation)
+++        {
+++            GlobalDeleteSymbolicLink(&(SymLinks[i]));
+++            FreePool(SymLinks[i].Buffer);
+++            continue;
+++        }
+++
+++        SymlinkInformation->Name = SymLinks[i];
+++        SymlinkInformation->Online = TRUE;
+++
+++        InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
+++                       &(SymlinkInformation->SymbolicLinksListEntry));
+++    }
+++
+++    /* Now, for all the recreated symlinks, notify their recreation */
+++    for (NextEntry = DeviceInformation->SymbolicLinksListHead.Flink;
+++         NextEntry != &(DeviceInformation->SymbolicLinksListHead);
+++         NextEntry = NextEntry->Flink)
+++    {
+++        SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+++
+++        SendLinkCreated(&(SymlinkInformation->Name));
+++    }
+++
+++    /* If we had saved links, it's time to free them */
+++    if (SavedLinkInformation)
+++    {
+++        MountMgrFreeSavedLink(SavedLinkInformation);
+++    }
+++
+++    /* If our device doesn't have a volume name */
+++    if (!IsVolumeName)
+++    {
+++        /* It's time to create one */
+++        Status = CreateNewVolumeName(&VolumeName, NULL);
+++        if (NT_SUCCESS(Status))
+++        {
+++            /* Write it to global database */
+++            RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
+++                                  DatabasePath,
+++                                  VolumeName.Buffer,
+++                                  REG_BINARY,
+++                                  UniqueId->UniqueId,
+++                                  UniqueId->UniqueIdLength);
+++
+++            /* And create the symlink */
+++            GlobalCreateSymbolicLink(&VolumeName, &TargetDeviceName);
+++
+++            SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
+++            if (!SymlinkInformation)
+++            {
+++                FreePool(VolumeName.Buffer);
+++            }
+++            /* Finally, associate it with the device and notify creation */
+++            else
+++            {
+++                SymlinkInformation->Name = VolumeName;
+++                SymlinkInformation->Online = TRUE;
+++                InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
+++                               &(SymlinkInformation->SymbolicLinksListEntry));
+++
+++                SendLinkCreated(&VolumeName);
+++            }
+++        }
+++    }
+++
+++    /* If we found a drive letter, then, ignore the suggested one */
+++    if (IsDrvLetter)
+++    {
+++        DeviceInformation->SuggestedDriveLetter = 0;
+++    }
+++    /* Else, it's time to set up one */
+++    else if (!DeviceExtension->NoAutoMount && !DeviceInformation->Removable &&
+++             DeviceExtension->AutomaticDriveLetter && HasGptDriveLetter &&
+++             DeviceInformation->SuggestedDriveLetter &&
+++             !HasNoDriveLetterEntry(UniqueId))
+++    {
+++        /* Create a new drive letter */
+++        Status = CreateNewDriveLetterName(&DriveLetter, &TargetDeviceName,
+++                                          DeviceInformation->SuggestedDriveLetter,
+++                                          NULL);
+++        if (!NT_SUCCESS(Status))
+++        {
+++            CreateNoDriveLetterEntry(UniqueId);
+++        }
+++        else
+++        {
+++            /* Save it to global database */
+++            RtlWriteRegistryValue(RTL_REGISTRY_ABSOLUTE,
+++                                  DatabasePath,
+++                                  DriveLetter.Buffer,
+++                                  REG_BINARY,
+++                                  UniqueId->UniqueId,
+++                                  UniqueId->UniqueIdLength);
+++
+++            /* Associate it with the device and notify creation */
+++            SymlinkInformation = AllocatePool(sizeof(SYMLINK_INFORMATION));
+++            if (!SymlinkInformation)
+++            {
+++                FreePool(DriveLetter.Buffer);
+++            }
+++            else
+++            {
+++                SymlinkInformation->Name = DriveLetter;
+++                SymlinkInformation->Online = TRUE;
+++                InsertTailList(&(DeviceInformation->SymbolicLinksListHead),
+++                               &(SymlinkInformation->SymbolicLinksListEntry));
+++
+++                SendLinkCreated(&DriveLetter);
+++            }
+++        }
+++    }
+++
+++    /* If required, register for notifications about the device */
+++    if (!FromVolume)
+++    {
+++        RegisterForTargetDeviceNotification(DeviceExtension, DeviceInformation);
+++    }
+++
+++    /* Finally, insert the device into our devices list */
+++    InsertTailList(&(DeviceExtension->DeviceListHead), &(DeviceInformation->DeviceListEntry));
+++
+++    /* Copy device unique ID */
+++    NewUniqueId = AllocatePool(UniqueId->UniqueIdLength + sizeof(MOUNTDEV_UNIQUE_ID));
+++    if (NewUniqueId)
+++    {
+++        NewUniqueId->UniqueIdLength = UniqueId->UniqueIdLength;
+++        RtlCopyMemory(NewUniqueId->UniqueId, UniqueId->UniqueId, UniqueId->UniqueIdLength);
+++    }
+++
+++    /* If device's offline or valid, skip its notifications */
+++    if (IsOff || Valid)
+++    {
+++        DeviceInformation->SkipNotifications = TRUE;
+++    }
+++
+++    /* In case device is valid and is set to no automount,
+++     * set it offline.
+++     */
+++    if (DeviceExtension->NoAutoMount || IsDrvLetter)
+++    {
+++        IsOff = !DeviceInformation->SkipNotifications;
+++    }
+++    else
+++    {
+++        IsOff = FALSE;
+++    }
+++
+++    /* Finally, release the exclusive lock */
+++    KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
+++
+++    /* If device is not offline, notify its arrival */
+++    if (!IsOff)
+++    {
+++        SendOnlineNotification(SymbolicName);
+++    }
+++
+++    /* If we had symlinks (from storage), free them */
+++    if (SymLinks)
+++    {
+++        FreePool(SymLinks);
+++    }
+++
+++    /* Notify about unique id change */
+++    if (NewUniqueId)
+++    {
+++        IssueUniqueIdChangeNotify(DeviceExtension, SymbolicName, NewUniqueId);
+++        FreePool(NewUniqueId);
+++    }
+++
+++    /* If this drive was set to have a drive letter automatically
+++     * Now it's back, local databases sync will be required
+++     */
+++    if (DeviceExtension->AutomaticDriveLetter)
+++    {
+++        KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
+++
+++        ReconcileThisDatabaseWithMaster(DeviceExtension, DeviceInformation);
+++
+++        NextEntry = DeviceExtension->DeviceListHead.Flink;
+++        CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
+++        while (CurrentDevice != DeviceInformation)
+++        {
+++            if (!CurrentDevice->NoDatabase)
+++            {
+++                ReconcileThisDatabaseWithMaster(DeviceExtension, CurrentDevice);
+++            }
+++
+++            NextEntry = NextEntry->Flink;
+++            CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
+++        }
+++
+++        KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
+++    }
+++
+++    return STATUS_SUCCESS;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++VOID
+++MountMgrMountedDeviceRemoval(IN PDEVICE_EXTENSION DeviceExtension,
+++                             IN PUNICODE_STRING DeviceName)
+++{
+++    PLIST_ENTRY NextEntry, DeviceEntry;
+++    PUNIQUE_ID_REPLICATE UniqueIdReplicate;
+++    PSYMLINK_INFORMATION SymlinkInformation;
+++    PASSOCIATED_DEVICE_ENTRY AssociatedDevice;
+++    PSAVED_LINK_INFORMATION SavedLinkInformation = NULL;
+++    PDEVICE_INFORMATION DeviceInformation, CurrentDevice;
+++
+++    /* Acquire device exclusively */
+++    KeWaitForSingleObject(&(DeviceExtension->DeviceLock), Executive, KernelMode, FALSE, NULL);
+++
+++    /* Look for the leaving device */
+++    for (NextEntry = DeviceExtension->DeviceListHead.Flink;
+++         NextEntry != &(DeviceExtension->DeviceListHead);
+++         NextEntry = NextEntry->Flink)
+++    {
+++        DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
+++
+++        if (!RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE))
+++        {
+++            break;
+++        }
+++    }
+++
+++    /* If we found it */
+++    if (NextEntry != &(DeviceExtension->DeviceListHead))
+++    {
+++        /* If it's asked to keep links, then, prepare to save them */
+++        if (DeviceInformation->KeepLinks)
+++        {
+++            SavedLinkInformation = AllocatePool(sizeof(SAVED_LINK_INFORMATION));
+++            if (!SavedLinkInformation)
+++            {
+++                DeviceInformation->KeepLinks = FALSE;
+++            }
+++        }
+++
+++        /* If it's possible (and asked), start to save them */
+++        if (DeviceInformation->KeepLinks)
+++        {
+++            InsertTailList(&(DeviceExtension->SavedLinksListHead), &(SavedLinkInformation->SavedLinksListEntry));
+++            InitializeListHead(&(SavedLinkInformation->SymbolicLinksListHead));
+++            SavedLinkInformation->UniqueId = DeviceInformation->UniqueId;
+++        }
+++
+++        /* For all the symlinks */
+++        while (!IsListEmpty(&(DeviceInformation->SymbolicLinksListHead)))
+++        {
+++            NextEntry = RemoveHeadList(&(DeviceInformation->SymbolicLinksListHead));
+++            SymlinkInformation = CONTAINING_RECORD(NextEntry, SYMLINK_INFORMATION, SymbolicLinksListEntry);
+++
+++            /* If we have to, save the link */
+++            if (DeviceInformation->KeepLinks)
+++            {
+++                InsertTailList(&(SavedLinkInformation->SymbolicLinksListHead), &(SymlinkInformation->SymbolicLinksListEntry));
+++            }
+++            /* Otherwise, just release it */
+++            else
+++            {
+++                GlobalDeleteSymbolicLink(&(SymlinkInformation->Name));
+++                FreePool(SymlinkInformation->Name.Buffer);
+++                FreePool(SymlinkInformation);
+++            }
+++        }
+++
+++        /* Free all the replicated unique IDs */
+++        while (!IsListEmpty(&(DeviceInformation->ReplicatedUniqueIdsListHead)))
+++        {
+++            NextEntry = RemoveHeadList(&(DeviceInformation->ReplicatedUniqueIdsListHead));
+++            UniqueIdReplicate = CONTAINING_RECORD(NextEntry, UNIQUE_ID_REPLICATE, ReplicatedUniqueIdsListEntry);
+++
+++
+++            FreePool(UniqueIdReplicate->UniqueId);
+++            FreePool(UniqueIdReplicate);
+++        }
+++
+++        while (!IsListEmpty(&(DeviceInformation->AssociatedDevicesHead)))
+++        {
+++            NextEntry = RemoveHeadList(&(DeviceInformation->AssociatedDevicesHead));
+++            AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
+++
+++            DeviceInformation->NoDatabase = TRUE;
+++            FreePool(AssociatedDevice->String.Buffer);
+++            FreePool(AssociatedDevice);
+++        }
+++
+++        /* Remove device from the device list */
+++        RemoveEntryList(&(DeviceInformation->DeviceListEntry));
+++
+++        /* If there are still devices, check if some were associated with ours */
+++        if (!IsListEmpty(&(DeviceInformation->DeviceListEntry)))
+++        {
+++            for (NextEntry = DeviceExtension->DeviceListHead.Flink;
+++                 NextEntry != &(DeviceExtension->DeviceListHead);
+++                 NextEntry = NextEntry->Flink)
+++            {
+++                CurrentDevice = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
+++
+++                /* And then, remove them */
+++                DeviceEntry = CurrentDevice->AssociatedDevicesHead.Flink;
+++                while (DeviceEntry != &(CurrentDevice->AssociatedDevicesHead))
+++                {
+++                    AssociatedDevice = CONTAINING_RECORD(NextEntry, ASSOCIATED_DEVICE_ENTRY, AssociatedDevicesEntry);
+++                    DeviceEntry = DeviceEntry->Flink;
+++
+++                    if (AssociatedDevice->DeviceInformation != DeviceInformation)
+++                    {
+++                        continue;
+++                    }
+++
+++                    RemoveEntryList(&(AssociatedDevice->AssociatedDevicesEntry));
+++                    FreePool(AssociatedDevice->String.Buffer);
+++                    FreePool(AssociatedDevice);
+++                }
+++            }
+++        }
+++
+++        /* Finally, clean up device name, symbolic name */
+++        FreePool(DeviceInformation->SymbolicName.Buffer);
+++        if (!DeviceInformation->KeepLinks)
+++        {
+++            FreePool(DeviceInformation->UniqueId);
+++        }
+++        FreePool(DeviceInformation->DeviceName.Buffer);
+++
+++        /* Unregister notifications */
+++        if (DeviceInformation->TargetDeviceNotificationEntry)
+++        {
+++            IoUnregisterPlugPlayNotification(DeviceInformation->TargetDeviceNotificationEntry);
+++        }
+++
+++        /*  And leave */
+++        FreePool(DeviceInformation);
+++    }
+++    else
+++    {
+++        /* We didn't find device, perhaps because it was offline */
+++        for (NextEntry = DeviceExtension->OfflineDeviceListHead.Flink;
+++             NextEntry != &(DeviceExtension->OfflineDeviceListHead);
+++             NextEntry = NextEntry->Flink)
+++        {
+++            DeviceInformation = CONTAINING_RECORD(NextEntry, DEVICE_INFORMATION, DeviceListEntry);
+++
+++            /* It was, remove it */
+++            if (RtlCompareUnicodeString(&(DeviceInformation->SymbolicName), DeviceName, TRUE) == 0)
+++            {
+++                RemoveEntryList(&(DeviceInformation->DeviceListEntry));
+++                MountMgrFreeDeadDeviceInfo(DeviceInformation);
+++                break;
+++            }
+++        }
+++    }
+++
+++    /* Releave driver */
+++    KeReleaseSemaphore(&(DeviceExtension->DeviceLock), IO_NO_INCREMENT, 1, FALSE);
+++}
+++
+++/*
+++ * @implemented
+++ */
+++NTSTATUS
+++NTAPI
+++MountMgrMountedDeviceNotification(IN PVOID NotificationStructure,
+++                                  IN PVOID Context)
+++{
+++    BOOLEAN OldState;
+++    PDEVICE_EXTENSION DeviceExtension;
+++    PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification;
+++
+++    /* Notification for a device arrived */
+++    /* Disable hard errors */
+++    OldState = PsGetThreadHardErrorsAreDisabled(PsGetCurrentThread());
+++    PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), TRUE);
+++
+++    DeviceExtension = Context;
+++    Notification = NotificationStructure;
+++
+++    /* Dispatch according to the event */
+++    if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_ARRIVAL))
+++    {
+++        MountMgrMountedDeviceArrival(DeviceExtension, Notification->SymbolicLinkName, FALSE);
+++    }
+++    else if (IsEqualGUID(&(Notification->Event), &GUID_DEVICE_INTERFACE_REMOVAL))
+++    {
+++        MountMgrMountedDeviceRemoval(DeviceExtension, Notification->SymbolicLinkName);
+++    }
+++
+++    /* Reset hard errors */
+++    PsSetThreadHardErrorsAreDisabled(PsGetCurrentThread(), OldState);
+++
+++    return STATUS_SUCCESS;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++NTSTATUS
+++NTAPI
+++MountMgrCreateClose(IN PDEVICE_OBJECT DeviceObject,
+++                    IN PIRP Irp)
+++{
+++    PIO_STACK_LOCATION Stack;
+++    NTSTATUS Status = STATUS_SUCCESS;
+++
+++    Stack = IoGetCurrentIrpStackLocation(Irp);
+++
+++    /* Allow driver opening for communication
+++     * as long as it's not taken for a directory
+++     */
+++    if (Stack->MajorFunction == IRP_MJ_CREATE &&
+++        Stack->Parameters.Create.Options & FILE_DIRECTORY_FILE)
+++    {
+++        Status = STATUS_NOT_A_DIRECTORY;
+++    }
+++
+++    Irp->IoStatus.Status = Status;
+++    Irp->IoStatus.Information = 0;
+++    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+++    return Status;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++VOID
+++NTAPI
+++MountMgrCancel(IN PDEVICE_OBJECT DeviceObject,
+++               IN PIRP Irp)
+++{
+++    RemoveEntryList(&(Irp->Tail.Overlay.ListEntry));
+++
+++    IoReleaseCancelSpinLock(Irp->CancelIrql);
+++
+++    Irp->IoStatus.Information = 0;
+++    Irp->IoStatus.Status = STATUS_CANCELLED;
+++    IofCompleteRequest(Irp, IO_NO_INCREMENT);
+++}
+++
+++/*
+++ * @implemented
+++ */
+++NTSTATUS
+++NTAPI
+++MountMgrCleanup(IN PDEVICE_OBJECT DeviceObject,
+++                IN PIRP Irp)
+++{
+++    PIRP ListIrp;
+++    KIRQL OldIrql;
+++    PLIST_ENTRY NextEntry;
+++    PFILE_OBJECT FileObject;
+++    PIO_STACK_LOCATION Stack;
+++    PDEVICE_EXTENSION DeviceExtension;
+++
+++    DeviceExtension = DeviceObject->DeviceExtension;
+++    Stack = IoGetCurrentIrpStackLocation(Irp);
+++    FileObject = Stack->FileObject;
+++
+++    IoAcquireCancelSpinLock(&OldIrql);
+++
+++    /* If IRP list if empty, it's OK */
+++    if (IsListEmpty(&(DeviceExtension->IrpListHead)))
+++    {
+++        IoReleaseCancelSpinLock(OldIrql);
+++
+++        Irp->IoStatus.Status = STATUS_SUCCESS;
+++        Irp->IoStatus.Information = 0;
+++        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+++
+++        return STATUS_SUCCESS;
+++    }
+++
+++    /* Otherwise, cancel all the IRPs */
+++    NextEntry = &(DeviceExtension->IrpListHead);
+++    do
+++    {
+++        ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
+++        if (IoGetCurrentIrpStackLocation(ListIrp)->FileObject == FileObject)
+++        {
+++            ListIrp->Cancel = TRUE;
+++            ListIrp->CancelIrql = OldIrql;
+++            ListIrp->CancelRoutine = NULL;
+++            MountMgrCancel(DeviceObject, ListIrp);
+++
+++            IoAcquireCancelSpinLock(&OldIrql);
+++        }
+++
+++        NextEntry = NextEntry->Flink;
+++    }
+++    while (NextEntry != &(DeviceExtension->IrpListHead));
+++
+++    IoReleaseCancelSpinLock(OldIrql);
+++
+++    Irp->IoStatus.Status = STATUS_SUCCESS;
+++    Irp->IoStatus.Information = 0;
+++    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+++
+++    return STATUS_SUCCESS;
+++}
+++
+++/*
+++ * @implemented
+++ */
+++NTSTATUS
+++NTAPI
+++MountMgrShutdown(IN PDEVICE_OBJECT DeviceObject,
+++                 IN PIRP Irp)
+++{
+++    PDEVICE_EXTENSION DeviceExtension;
+++
+++    DeviceExtension = DeviceObject->DeviceExtension;
+++
+++    InterlockedExchange(&Unloading, TRUE);
+++
+++    KeInitializeEvent(&UnloadEvent, NotificationEvent, FALSE);
+++
+++    /* Wait for workers */
+++    if (InterlockedIncrement(&(DeviceExtension->WorkerReferences)))
+++    {
+++        KeReleaseSemaphore(&(DeviceExtension->WorkerSemaphore),
+++                           IO_NO_INCREMENT,
+++                           1,
+++                           FALSE);
+++        KeWaitForSingleObject(&UnloadEvent, Executive, KernelMode, FALSE, NULL);
+++    }
+++    else
+++    {
+++        InterlockedDecrement(&(DeviceExtension->WorkerReferences));
+++    }
+++
+++    Irp->IoStatus.Status = STATUS_SUCCESS;
+++    Irp->IoStatus.Information = 0;
+++    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+++
+++    return STATUS_SUCCESS;
+++}
+++
+++/* FUNCTIONS ****************************************************************/
+++
+++NTSTATUS
+++NTAPI
+++DriverEntry(IN PDRIVER_OBJECT DriverObject,
+++            IN PUNICODE_STRING RegistryPath)
+++{
+++    NTSTATUS Status;
+++    PDEVICE_OBJECT DeviceObject;
+++    PDEVICE_EXTENSION DeviceExtension;
+++
+++    RtlCreateRegistryKey(RTL_REGISTRY_ABSOLUTE, DatabasePath);
+++
+++    Status = IoCreateDevice(DriverObject,
+++                            sizeof(DEVICE_EXTENSION),
+++                            &DeviceMount,
+++                            FILE_DEVICE_NETWORK,
+++                            FILE_DEVICE_SECURE_OPEN,
+++                            FALSE,
+++                            &DeviceObject);
+++    if (!NT_SUCCESS(Status))
+++    {
+++        return Status;
+++    }
+++
+++    DriverObject->DriverUnload = MountMgrUnload;
+++
+++    DeviceExtension = DeviceObject->DeviceExtension;
+++    RtlZeroMemory(DeviceExtension, sizeof(DEVICE_EXTENSION));
+++    DeviceExtension->DeviceObject = DeviceObject;
+++    DeviceExtension->DriverObject = DriverObject;
+++
+++    InitializeListHead(&(DeviceExtension->DeviceListHead));
+++    InitializeListHead(&(DeviceExtension->OfflineDeviceListHead));
+++
+++    KeInitializeSemaphore(&(DeviceExtension->DeviceLock), 1, 1);
+++    KeInitializeSemaphore(&(DeviceExtension->RemoteDatabaseLock), 1, 1);
+++
+++    InitializeListHead(&(DeviceExtension->IrpListHead));
+++    DeviceExtension->EpicNumber = 1;
+++
+++    InitializeListHead(&(DeviceExtension->SavedLinksListHead));
+++
+++    InitializeListHead(&(DeviceExtension->WorkerQueueListHead));
+++    KeInitializeSemaphore(&(DeviceExtension->WorkerSemaphore), 0, MAXLONG);
+++    DeviceExtension->WorkerReferences = -1;
+++    KeInitializeSpinLock(&(DeviceExtension->WorkerLock));
+++
+++    InitializeListHead(&(DeviceExtension->UniqueIdWorkerItemListHead));
+++    InitializeListHead(&(DeviceExtension->OnlineNotificationListHead));
+++    DeviceExtension->OnlineNotificationCount = 1;
+++
+++    DeviceExtension->RegistryPath.Length = RegistryPath->Length;
+++    DeviceExtension->RegistryPath.MaximumLength = RegistryPath->Length + sizeof(WCHAR);
+++    DeviceExtension->RegistryPath.Buffer = AllocatePool(DeviceExtension->RegistryPath.MaximumLength);
+++    if (!DeviceExtension->RegistryPath.Buffer)
+++    {
+++        IoDeleteDevice(DeviceObject);
+++        return STATUS_INSUFFICIENT_RESOURCES;
+++    }
+++
+++    RtlCopyUnicodeString(&(DeviceExtension->RegistryPath), RegistryPath);
+++
+++    DeviceExtension->NoAutoMount = MountmgrReadNoAutoMount(&(DeviceExtension->RegistryPath));
+++
+++    GlobalCreateSymbolicLink(&DosDevicesMount, &DeviceMount);
+++
+++    /* Register for device arrival & removal. Ask to be notified for already
+++     * present devices
+++     */
+++    Status = IoRegisterPlugPlayNotification(EventCategoryDeviceInterfaceChange,
+++                                            PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
+++                                            &MountedDevicesGuid,
+++                                            DriverObject,
+++                                            MountMgrMountedDeviceNotification,
+++                                            DeviceObject,
+++                                            &(DeviceExtension->NotificationEntry));
+++
+++    if (!NT_SUCCESS(Status))
+++    {
+++        IoDeleteDevice(DeviceObject);
+++        return Status;
+++    }
+++
+++    DriverObject->MajorFunction[IRP_MJ_CREATE]         =
+++    DriverObject->MajorFunction[IRP_MJ_CLOSE]          = MountMgrCreateClose;
+++    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = MountMgrDeviceControl;
+++    DriverObject->MajorFunction[IRP_MJ_CLEANUP]        = MountMgrCleanup;
+++    DriverObject->MajorFunction[IRP_MJ_SHUTDOWN]       = MountMgrShutdown;
+++
+++    gdeviceObject = DeviceObject;
+++
+++    Status = IoRegisterShutdownNotification(DeviceObject);
+++    if (!NT_SUCCESS(Status))
+++    {
+++        IoDeleteDevice(DeviceObject);
+++    }
+++
+++    return Status;
+++}
index 0000000,0000000,52aa848..52aa848
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,6051356,6051356..6051356
mode 000000,100644,100644..100644
--- /dev/null
index 0000000,0000000,4fa5c64..4fa5c64
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,f5f6922..f5f6922
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,27df904..27df904
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,deb67f4..deb67f4
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,c5419c6..c5419c6
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,cfaadc6..cfaadc6
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,d443106..d443106
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,6cc8ed3..6cc8ed3
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,a862045..a862045
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,fd9c46d..fd9c46d
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,ce9f626..ce9f626
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,bc606bb..bc606bb
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,904f6d2..904f6d2
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,b713b70..b713b70
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,78048fd..78048fd
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 0000000,0000000,cfb1f95..cfb1f95
mode 000000,000000,100644..100644
--- /dev/null
--- /dev/null
index 3cf6c95,0000000,e1bbe58..e1bbe58
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,1035 -1,0 -1,1102 +1,1102 @@@@
 + /*
 +  * COPYRIGHT:       See COPYING in the top level directory
 +  * PROJECT:         ReactOS Keyboard class driver
 +  * FILE:            drivers/kbdclass/kbdclass.c
 +  * PURPOSE:         Keyboard class driver
 +  *
 +  * PROGRAMMERS:     HervĂ© Poussineau (hpoussin@reactos.org)
 +  */
 + 
 + #define INITGUID
 + #include "kbdclass.h"
 + 
 + static DRIVER_UNLOAD DriverUnload;
 + static DRIVER_DISPATCH ClassCreate;
 + static DRIVER_DISPATCH ClassClose;
 + static DRIVER_DISPATCH ClassCleanup;
 + static DRIVER_DISPATCH ClassRead;
 + static DRIVER_DISPATCH ClassDeviceControl;
 + static DRIVER_DISPATCH IrpStub;
 + static DRIVER_ADD_DEVICE ClassAddDevice;
 + static DRIVER_STARTIO ClassStartIo;
 + static DRIVER_CANCEL ClassCancelRoutine;
 + static NTSTATUS
 + HandleReadIrp(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp,
 +      BOOLEAN IsInStartIo);
 + 
 + static VOID NTAPI
 + DriverUnload(IN PDRIVER_OBJECT DriverObject)
 + {
 +      // nothing to do here yet
 + }
 + 
 + static NTSTATUS NTAPI
 + ClassCreate(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp)
 + {
 +      TRACE_(CLASS_NAME, "IRP_MJ_CREATE\n");
 + 
 +      if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
 +              return ForwardIrpAndForget(DeviceObject, Irp);
 + 
 +      /* FIXME: open all associated Port devices */
 +      Irp->IoStatus.Status = STATUS_SUCCESS;
 +      Irp->IoStatus.Information = 0;
 +      IoCompleteRequest(Irp, IO_NO_INCREMENT);
 +      return STATUS_SUCCESS;
 + }
 + 
 + static NTSTATUS NTAPI
 + ClassClose(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp)
 + {
 +      TRACE_(CLASS_NAME, "IRP_MJ_CLOSE\n");
 + 
 +      if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
 +              return ForwardIrpAndForget(DeviceObject, Irp);
 + 
 +      /* FIXME: close all associated Port devices */
 +      Irp->IoStatus.Status = STATUS_SUCCESS;
 +      Irp->IoStatus.Information = 0;
 +      IoCompleteRequest(Irp, IO_NO_INCREMENT);
 +      return STATUS_SUCCESS;
 + }
 + 
 + static NTSTATUS NTAPI
 + ClassCleanup(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp)
 + {
 +      TRACE_(CLASS_NAME, "IRP_MJ_CLEANUP\n");
 + 
 +      if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
 +              return ForwardIrpAndForget(DeviceObject, Irp);
 + 
 +      /* FIXME: cleanup all associated Port devices */
 +      Irp->IoStatus.Status = STATUS_SUCCESS;
 +      Irp->IoStatus.Information = 0;
 +      IoCompleteRequest(Irp, IO_NO_INCREMENT);
 +      return STATUS_SUCCESS;
 + }
 + 
 + static NTSTATUS NTAPI
 + ClassRead(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp)
 + {
 +      PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
 +      KIRQL OldIrql;
 +      NTSTATUS Status;
 + 
 +      TRACE_(CLASS_NAME, "IRP_MJ_READ\n");
 + 
 +      ASSERT(DeviceExtension->Common.IsClassDO);
 + 
 +      if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
 +              return ForwardIrpAndForget(DeviceObject, Irp);
 + 
 +      if (IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length < sizeof(KEYBOARD_INPUT_DATA))
 +      {
 +              Irp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
 +              Irp->IoStatus.Information = 0;
 +              IoCompleteRequest(Irp, IO_NO_INCREMENT);
 + 
 +              return STATUS_BUFFER_TOO_SMALL;
 +      }
 + 
 +      KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
 +      Status = HandleReadIrp(DeviceObject, Irp, FALSE);
 +      KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
 +      return Status;
 + }
 + 
 + static NTSTATUS NTAPI
 + ClassDeviceControl(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp)
 + {
 +      //PCLASS_DEVICE_EXTENSION DeviceExtension;
 +      NTSTATUS Status = STATUS_NOT_SUPPORTED;
 + 
 +      TRACE_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL\n");
 + 
 +      if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
 +              return ForwardIrpAndForget(DeviceObject, Irp);
 + 
 +      //DeviceExtension = (PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
 + 
 +      switch (IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode)
 +      {
 +              case IOCTL_KEYBOARD_QUERY_ATTRIBUTES:
 +              case IOCTL_KEYBOARD_QUERY_INDICATOR_TRANSLATION:
 +              case IOCTL_KEYBOARD_QUERY_INDICATORS:
 +              case IOCTL_KEYBOARD_QUERY_TYPEMATIC:
 +              {
 +                      /* FIXME: We hope that all devices will return the same result.
 +                       * Ask only the first one */
 +                      PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;
 +                      if (Head->Flink != Head)
 +                      {
 +                              /* We have at least one device */
 +                              PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Head->Flink, PORT_DEVICE_EXTENSION, ListEntry);
 +                              IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
 +                              IoSkipCurrentIrpStackLocation(Irp);
 +                              return IoCallDriver(DevExt->DeviceObject, Irp);
 +                      }
 +                      break;
 +              }
 +              case IOCTL_KEYBOARD_SET_INDICATORS:
 +              case IOCTL_KEYBOARD_SET_TYPEMATIC: /* not in MSDN, would seem logical */
 +              {
 +                      /* Send it to all associated Port devices */
 +                      PLIST_ENTRY Head = &((PCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->ListHead;
 +                      PLIST_ENTRY Entry = Head->Flink;
 +                      Status = STATUS_SUCCESS;
 +                      while (Entry != Head)
 +                      {
 +                              PPORT_DEVICE_EXTENSION DevExt = CONTAINING_RECORD(Entry, PORT_DEVICE_EXTENSION, ListEntry);
 +                              NTSTATUS IntermediateStatus;
 + 
 +                              IoGetCurrentIrpStackLocation(Irp)->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
 +                              IntermediateStatus = ForwardIrpAndWait(DevExt->DeviceObject, Irp);
 +                              if (!NT_SUCCESS(IntermediateStatus))
 +                                      Status = IntermediateStatus;
 +                              Entry = Entry->Flink;
 +                      }
 +                      break;
 +              }
 +              default:
 +                      WARN_(CLASS_NAME, "IRP_MJ_DEVICE_CONTROL / unknown I/O control code 0x%lx\n",
 +                              IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.IoControlCode);
 +                      ASSERT(FALSE);
 +                      break;
 +      }
 + 
 +      Irp->IoStatus.Status = Status;
 +      Irp->IoStatus.Information = 0;
 +      IoCompleteRequest(Irp, IO_NO_INCREMENT);
 + 
 +      return Status;
 + }
 + 
 + static NTSTATUS NTAPI
 + IrpStub(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp)
 + {
 +      NTSTATUS Status = STATUS_NOT_SUPPORTED;
 + 
 +      if (!((PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->IsClassDO)
 +      {
 +              /* Forward some IRPs to lower device */
 +              switch (IoGetCurrentIrpStackLocation(Irp)->MajorFunction)
 +              {
 +                      case IRP_MJ_PNP:
 +                      case IRP_MJ_INTERNAL_DEVICE_CONTROL:
 +                              return ForwardIrpAndForget(DeviceObject, Irp);
 +                      default:
 +                      {
 +                              ERR_(CLASS_NAME, "Port DO stub for major function 0x%lx\n",
 +                                      IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
 +                              ASSERT(FALSE);
 +                      }
 +              }
 +      }
 +      else
 +      {
 +              ERR_(CLASS_NAME, "Class DO stub for major function 0x%lx\n",
 +                      IoGetCurrentIrpStackLocation(Irp)->MajorFunction);
 +              ASSERT(FALSE);
 +      }
 + 
 +      Irp->IoStatus.Status = Status;
 +      IoCompleteRequest(Irp, IO_NO_INCREMENT);
 +      return Status;
 + }
 + 
 + static NTSTATUS
 + ReadRegistryEntries(
 +      IN PUNICODE_STRING RegistryPath,
 +      IN PCLASS_DRIVER_EXTENSION DriverExtension)
 + {
 +      UNICODE_STRING ParametersRegistryKey;
 +      RTL_QUERY_REGISTRY_TABLE Parameters[4];
 +      NTSTATUS Status;
 + 
 +      /* HACK: We don't support multiple devices with this disabled */
 +      ULONG DefaultConnectMultiplePorts = 1;
 +      ULONG DefaultDataQueueSize = 0x64;
 +      PCWSTR DefaultDeviceBaseName = L"KeyboardClass";
 + 
 +      ParametersRegistryKey.Length = 0;
 +      ParametersRegistryKey.MaximumLength = RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(UNICODE_NULL);
 +      ParametersRegistryKey.Buffer = ExAllocatePoolWithTag(PagedPool, ParametersRegistryKey.MaximumLength, CLASS_TAG);
 +      if (!ParametersRegistryKey.Buffer)
 +      {
 +              WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
 +              return STATUS_NO_MEMORY;
 +      }
 +      RtlCopyUnicodeString(&ParametersRegistryKey, RegistryPath);
 +      RtlAppendUnicodeToString(&ParametersRegistryKey, L"\\Parameters");
 +      ParametersRegistryKey.Buffer[ParametersRegistryKey.Length / sizeof(WCHAR)] = UNICODE_NULL;
 + 
 +      RtlZeroMemory(Parameters, sizeof(Parameters));
 + 
 +      Parameters[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
 +      Parameters[0].Name = L"ConnectMultiplePorts";
 +      Parameters[0].EntryContext = &DriverExtension->ConnectMultiplePorts;
 +      Parameters[0].DefaultType = REG_DWORD;
 +      Parameters[0].DefaultData = &DefaultConnectMultiplePorts;
 +      Parameters[0].DefaultLength = sizeof(ULONG);
 + 
 +      Parameters[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
 +      Parameters[1].Name = L"KeyboardDataQueueSize";
 +      Parameters[1].EntryContext = &DriverExtension->DataQueueSize;
 +      Parameters[1].DefaultType = REG_DWORD;
 +      Parameters[1].DefaultData = &DefaultDataQueueSize;
 +      Parameters[1].DefaultLength = sizeof(ULONG);
 + 
 +      Parameters[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_REGISTRY_OPTIONAL;
 +      Parameters[2].Name = L"KeyboardDeviceBaseName";
 +      Parameters[2].EntryContext = &DriverExtension->DeviceBaseName;
 +      Parameters[2].DefaultType = REG_SZ;
 +      Parameters[2].DefaultData = (PVOID)DefaultDeviceBaseName;
 +      Parameters[2].DefaultLength = 0;
 + 
 +      Status = RtlQueryRegistryValues(
 +              RTL_REGISTRY_ABSOLUTE,
 +              ParametersRegistryKey.Buffer,
 +              Parameters,
 +              NULL,
 +              NULL);
 + 
 +      if (NT_SUCCESS(Status))
 +      {
 +              /* Check values */
 +              if (DriverExtension->ConnectMultiplePorts != 0
 +                      && DriverExtension->ConnectMultiplePorts != 1)
 +              {
 +                      DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
 +              }
 +              if (DriverExtension->DataQueueSize == 0)
 +              {
 +                      DriverExtension->DataQueueSize = DefaultDataQueueSize;
 +              }
 +      }
 +      else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
 +      {
 +              /* Registry path doesn't exist. Set defaults */
 +              DriverExtension->ConnectMultiplePorts = DefaultConnectMultiplePorts;
 +              DriverExtension->DataQueueSize = DefaultDataQueueSize;
 +              if (RtlCreateUnicodeString(&DriverExtension->DeviceBaseName, DefaultDeviceBaseName))
 +                      Status = STATUS_SUCCESS;
 +              else
 +                      Status = STATUS_NO_MEMORY;
 +      }
 + 
 +      ExFreePoolWithTag(ParametersRegistryKey.Buffer, CLASS_TAG);
 +      return Status;
 + }
 + 
 + static NTSTATUS
 + CreateClassDeviceObject(
 +      IN PDRIVER_OBJECT DriverObject,
 +      OUT PDEVICE_OBJECT *ClassDO OPTIONAL)
 + {
 +      PCLASS_DRIVER_EXTENSION DriverExtension;
 +      ULONG DeviceId = 0;
 +      ULONG PrefixLength;
 +      UNICODE_STRING DeviceNameU;
 +      PWSTR DeviceIdW = NULL; /* Pointer into DeviceNameU.Buffer */
 +      PDEVICE_OBJECT Fdo;
 +      PCLASS_DEVICE_EXTENSION DeviceExtension;
 +      NTSTATUS Status;
 + 
 +      TRACE_(CLASS_NAME, "CreateClassDeviceObject(0x%p)\n", DriverObject);
 + 
 +      /* Create new device object */
 +      DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
 +      DeviceNameU.Length = 0;
 +      DeviceNameU.MaximumLength =
 +              wcslen(L"\\Device\\") * sizeof(WCHAR)    /* "\Device\" */
 +              + DriverExtension->DeviceBaseName.Length /* "KeyboardClass" */
 +              + 4 * sizeof(WCHAR)                      /* Id between 0 and 9999 */
 +              + sizeof(UNICODE_NULL);                  /* Final NULL char */
 +      DeviceNameU.Buffer = ExAllocatePoolWithTag(PagedPool, DeviceNameU.MaximumLength, CLASS_TAG);
 +      if (!DeviceNameU.Buffer)
 +      {
 +              WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
 +              return STATUS_NO_MEMORY;
 +      }
 +      Status = RtlAppendUnicodeToString(&DeviceNameU, L"\\Device\\");
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status);
 +              goto cleanup;
 +      }
 +      Status = RtlAppendUnicodeStringToString(&DeviceNameU, &DriverExtension->DeviceBaseName);
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status);
 +              goto cleanup;
 +      }
 +      PrefixLength = DeviceNameU.MaximumLength - 4 * sizeof(WCHAR) - sizeof(UNICODE_NULL);
 +      DeviceIdW = &DeviceNameU.Buffer[PrefixLength / sizeof(WCHAR)];
 +      while (DeviceId < 9999)
 +      {
 +              DeviceNameU.Length = (USHORT)(PrefixLength + swprintf(DeviceIdW, L"%lu", DeviceId) * sizeof(WCHAR));
 +              Status = IoCreateDevice(
 +                      DriverObject,
 +                      sizeof(CLASS_DEVICE_EXTENSION),
 +                      &DeviceNameU,
 +                      FILE_DEVICE_KEYBOARD,
 +                      FILE_DEVICE_SECURE_OPEN,
 +                      FALSE,
 +                      &Fdo);
 +              if (NT_SUCCESS(Status))
 +                      goto cleanup;
 +              else if (Status != STATUS_OBJECT_NAME_COLLISION)
 +              {
 +                      WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
 +                      goto cleanup;
 +              }
 +              DeviceId++;
 +      }
 +      WARN_(CLASS_NAME, "Too many devices starting with '\\Device\\%wZ'\n", &DriverExtension->DeviceBaseName);
 +      Status = STATUS_TOO_MANY_NAMES;
 + cleanup:
 +      if (!NT_SUCCESS(Status))
 +      {
 +              ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
 +              return Status;
 +      }
 + 
 +      DeviceExtension = (PCLASS_DEVICE_EXTENSION)Fdo->DeviceExtension;
 +      RtlZeroMemory(DeviceExtension, sizeof(CLASS_DEVICE_EXTENSION));
 +      DeviceExtension->Common.IsClassDO = TRUE;
 +      DeviceExtension->DriverExtension = DriverExtension;
 +      InitializeListHead(&DeviceExtension->ListHead);
 +      KeInitializeSpinLock(&DeviceExtension->ListSpinLock);
 +      KeInitializeSpinLock(&DeviceExtension->SpinLock);
 +      DeviceExtension->InputCount = 0;
 +      DeviceExtension->PortData = ExAllocatePoolWithTag(NonPagedPool, DeviceExtension->DriverExtension->DataQueueSize * sizeof(KEYBOARD_INPUT_DATA), CLASS_TAG);
 +      if (!DeviceExtension->PortData)
 +      {
 +              ExFreePoolWithTag(DeviceNameU.Buffer, CLASS_TAG);
 +              return STATUS_NO_MEMORY;
 +      }
 +      DeviceExtension->DeviceName = DeviceNameU.Buffer;
 +      Fdo->Flags |= DO_POWER_PAGABLE;
 +      Fdo->Flags |= DO_BUFFERED_IO; /* FIXME: Why is it needed for 1st stage setup? */
 +      Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
 + 
 +      /* Add entry entry to HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
 +      RtlWriteRegistryValue(
 +              RTL_REGISTRY_DEVICEMAP,
 +              DriverExtension->DeviceBaseName.Buffer,
 +              DeviceExtension->DeviceName,
 +              REG_SZ,
 +              DriverExtension->RegistryPath.Buffer,
 +              DriverExtension->RegistryPath.MaximumLength);
 + 
 +      if (ClassDO)
 +              *ClassDO = Fdo;
 + 
 +      return STATUS_SUCCESS;
 + }
 + 
 + static NTSTATUS
 + FillEntries(
 +      IN PDEVICE_OBJECT ClassDeviceObject,
 +      IN PIRP Irp,
 +      IN PKEYBOARD_INPUT_DATA DataStart,
 +      IN SIZE_T NumberOfEntries)
 + {
 +      NTSTATUS Status = STATUS_SUCCESS;
 + 
 +      if (ClassDeviceObject->Flags & DO_BUFFERED_IO)
 +      {
 +              RtlCopyMemory(
 +                      Irp->AssociatedIrp.SystemBuffer,
 +                      DataStart,
 +                      NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
 +      }
 +      else if (ClassDeviceObject->Flags & DO_DIRECT_IO)
 +      {
 +              PVOID DestAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
 +              if (DestAddress)
 +              {
 +                      RtlCopyMemory(
 +                              DestAddress,
 +                              DataStart,
 +                              NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
 +              }
 +              else
 +                      Status = STATUS_UNSUCCESSFUL;
 +      }
 +      else
 +      {
 +              _SEH2_TRY
 +              {
 +                      RtlCopyMemory(
 +                              Irp->UserBuffer,
 +                              DataStart,
 +                              NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA));
 +              }
 +              _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
 +              {
 +                      Status = _SEH2_GetExceptionCode();
 +              }
 +              _SEH2_END;
 +      }
 + 
 +      return Status;
 + }
 + 
 + static BOOLEAN NTAPI
 + ClassCallback(
 +      IN PDEVICE_OBJECT ClassDeviceObject,
 +      IN OUT PKEYBOARD_INPUT_DATA DataStart,
 +      IN PKEYBOARD_INPUT_DATA DataEnd,
 +      IN OUT PULONG ConsumedCount)
 + {
 +      PCLASS_DEVICE_EXTENSION ClassDeviceExtension = ClassDeviceObject->DeviceExtension;
 +      KIRQL OldIrql;
 +      SIZE_T InputCount = DataEnd - DataStart;
 +      SIZE_T ReadSize;
 + 
 +      TRACE_(CLASS_NAME, "ClassCallback()\n");
 + 
 +      ASSERT(ClassDeviceExtension->Common.IsClassDO);
 + 
 +      KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
 +      if (InputCount > 0)
 +      {
 +              if (ClassDeviceExtension->InputCount + InputCount > ClassDeviceExtension->DriverExtension->DataQueueSize)
 +              {
 +                      /*
 +                       * We're exceeding the buffer, and data will be thrown away...
 +                       * FIXME: What could we do, as we are at DISPATCH_LEVEL?
 +                       */
 +                      ReadSize = ClassDeviceExtension->DriverExtension->DataQueueSize - ClassDeviceExtension->InputCount;
 +              }
 +              else
 +                      ReadSize = InputCount;
 + 
 +              /*
 +               * Move the input data from the port data queue to our class data
 +               * queue.
 +               */
 +              RtlCopyMemory(
 +                      &ClassDeviceExtension->PortData[ClassDeviceExtension->InputCount],
 +                      (PCHAR)DataStart,
 +                      sizeof(KEYBOARD_INPUT_DATA) * ReadSize);
 + 
 +              /* Move the counter up */
 +              ClassDeviceExtension->InputCount += ReadSize;
 + 
 +              (*ConsumedCount) += (ULONG)ReadSize;
 + 
 +              /* Complete pending IRP (if any) */
 +              if (ClassDeviceExtension->PendingIrp)
 +                      HandleReadIrp(ClassDeviceObject, ClassDeviceExtension->PendingIrp, FALSE);
 +      }
 +      KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
 + 
 +      TRACE_(CLASS_NAME, "Leaving ClassCallback()\n");
 +      return TRUE;
 + }
 + 
 + /* Send IOCTL_INTERNAL_*_CONNECT to port */
 + static NTSTATUS
 + ConnectPortDriver(
 +      IN PDEVICE_OBJECT PortDO,
 +      IN PDEVICE_OBJECT ClassDO)
 + {
 +      KEVENT Event;
 +      PIRP Irp;
 +      IO_STATUS_BLOCK IoStatus;
 +      CONNECT_DATA ConnectData;
 +      NTSTATUS Status;
 + 
 +      TRACE_(CLASS_NAME, "Connecting PortDO %p to ClassDO %p\n", PortDO, ClassDO);
 + 
 +      KeInitializeEvent(&Event, NotificationEvent, FALSE);
 + 
 +      ConnectData.ClassDeviceObject = ClassDO;
 +      ConnectData.ClassService      = ClassCallback;
 + 
 +      Irp = IoBuildDeviceIoControlRequest(
 +              IOCTL_INTERNAL_KEYBOARD_CONNECT,
 +              PortDO,
 +              &ConnectData, sizeof(CONNECT_DATA),
 +              NULL, 0,
 +              TRUE, &Event, &IoStatus);
 +      if (!Irp)
 +              return STATUS_INSUFFICIENT_RESOURCES;
 + 
 +      Status = IoCallDriver(PortDO, Irp);
 + 
 +      if (Status == STATUS_PENDING)
 +              KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
 +      else
 +              IoStatus.Status = Status;
 + 
 +      if (NT_SUCCESS(IoStatus.Status))
 +      {
 +              ObReferenceObject(PortDO);
 +              ExInterlockedInsertTailList(
 +                      &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListHead,
 +                      &((PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension)->ListEntry,
 +                      &((PCLASS_DEVICE_EXTENSION)ClassDO->DeviceExtension)->ListSpinLock);
 +              if (ClassDO->StackSize <= PortDO->StackSize)
 +              {
 +                      /* Increase the stack size, in case we have to
 +                       * forward some IRPs to the port device object
 +                       */
 +                      ClassDO->StackSize = PortDO->StackSize + 1;
 +              }
 +      }
 + 
 +      return IoStatus.Status;
 + }
 + 
 + /* Send IOCTL_INTERNAL_*_DISCONNECT to port + destroy the Port DO */
 + static VOID
 + DestroyPortDriver(
 +      IN PDEVICE_OBJECT PortDO)
 + {
 +      PPORT_DEVICE_EXTENSION DeviceExtension;
 +      PCLASS_DEVICE_EXTENSION ClassDeviceExtension;
 +      PCLASS_DRIVER_EXTENSION DriverExtension;
 +      KEVENT Event;
 +      PIRP Irp;
 +      IO_STATUS_BLOCK IoStatus;
 +      KIRQL OldIrql;
 +      NTSTATUS Status;
 + 
 +      TRACE_(CLASS_NAME, "Destroying PortDO %p\n", PortDO);
 + 
 +      DeviceExtension = (PPORT_DEVICE_EXTENSION)PortDO->DeviceExtension;
 +      ClassDeviceExtension = DeviceExtension->ClassDO->DeviceExtension;
 +      DriverExtension = IoGetDriverObjectExtension(PortDO->DriverObject, PortDO->DriverObject);
 + 
 +      /* Send IOCTL_INTERNAL_*_DISCONNECT */
 +      KeInitializeEvent(&Event, NotificationEvent, FALSE);
 +      Irp = IoBuildDeviceIoControlRequest(
 +              IOCTL_INTERNAL_KEYBOARD_DISCONNECT,
 +              PortDO,
 +              NULL, 0,
 +              NULL, 0,
 +              TRUE, &Event, &IoStatus);
 +      if (Irp)
 +      {
 +              Status = IoCallDriver(PortDO, Irp);
 +              if (Status == STATUS_PENDING)
 +                      KeWaitForSingleObject(&Event, Suspended, KernelMode, FALSE, NULL);
 +      }
 + 
 +      /* Remove from ClassDeviceExtension->ListHead list */
 +      KeAcquireSpinLock(&ClassDeviceExtension->ListSpinLock, &OldIrql);
 +      RemoveHeadList(DeviceExtension->ListEntry.Blink);
 +      KeReleaseSpinLock(&ClassDeviceExtension->ListSpinLock, OldIrql);
 + 
 +      /* Remove entry from HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\[DeviceBaseName] */
 +      RtlDeleteRegistryValue(
 +              RTL_REGISTRY_DEVICEMAP,
 +              DriverExtension->DeviceBaseName.Buffer,
 +              ClassDeviceExtension->DeviceName);
 + 
 +      if (DeviceExtension->LowerDevice)
 +              IoDetachDevice(DeviceExtension->LowerDevice);
 +      ObDereferenceObject(PortDO);
 + 
 +      if (!DriverExtension->ConnectMultiplePorts && DeviceExtension->ClassDO)
 +      {
 +              ExFreePoolWithTag(ClassDeviceExtension->PortData, CLASS_TAG);
 +              ExFreePoolWithTag((PVOID)ClassDeviceExtension->DeviceName, CLASS_TAG);
 +              IoDeleteDevice(DeviceExtension->ClassDO);
 +      }
 + 
 +      IoDeleteDevice(PortDO);
 + }
 + 
 + static NTSTATUS NTAPI
 + ClassAddDevice(
 +      IN PDRIVER_OBJECT DriverObject,
 +      IN PDEVICE_OBJECT Pdo)
 + {
 +      PCLASS_DRIVER_EXTENSION DriverExtension;
 +      PDEVICE_OBJECT Fdo = NULL;
 +      PPORT_DEVICE_EXTENSION DeviceExtension = NULL;
 +      NTSTATUS Status;
 + 
 +      TRACE_(CLASS_NAME, "ClassAddDevice called. Pdo = 0x%p\n", Pdo);
 + 
 +      DriverExtension = IoGetDriverObjectExtension(DriverObject, DriverObject);
 + 
 +      if (Pdo == NULL)
 +              /* We may get a NULL Pdo at the first call as we're a legacy driver. Ignore it */
 +              return STATUS_SUCCESS;
 + 
 +      /* Create new device object */
 +      Status = IoCreateDevice(
 +              DriverObject,
 +              sizeof(PORT_DEVICE_EXTENSION),
 +              NULL,
 +              Pdo->DeviceType,
 +              Pdo->Characteristics & FILE_DEVICE_SECURE_OPEN ? FILE_DEVICE_SECURE_OPEN : 0,
 +              FALSE,
 +              &Fdo);
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "IoCreateDevice() failed with status 0x%08lx\n", Status);
 +              goto cleanup;
 +      }
 +      IoSetStartIoAttributes(Fdo, TRUE, TRUE);
 + 
 +      DeviceExtension = (PPORT_DEVICE_EXTENSION)Fdo->DeviceExtension;
 +      RtlZeroMemory(DeviceExtension, sizeof(PORT_DEVICE_EXTENSION));
 +      DeviceExtension->Common.IsClassDO = FALSE;
 +      DeviceExtension->DeviceObject = Fdo;
 +      DeviceExtension->PnpState = dsStopped;
 +      Status = IoAttachDeviceToDeviceStackSafe(Fdo, Pdo, &DeviceExtension->LowerDevice);
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "IoAttachDeviceToDeviceStackSafe() failed with status 0x%08lx\n", Status);
 +              goto cleanup;
 +      }
 +      if (DeviceExtension->LowerDevice->Flags & DO_POWER_PAGABLE)
 +              Fdo->Flags |= DO_POWER_PAGABLE;
 +      if (DeviceExtension->LowerDevice->Flags & DO_BUFFERED_IO)
 +              Fdo->Flags |= DO_BUFFERED_IO;
 +      if (DeviceExtension->LowerDevice->Flags & DO_DIRECT_IO)
 +              Fdo->Flags |= DO_DIRECT_IO;
 + 
 +      if (DriverExtension->ConnectMultiplePorts)
 +              DeviceExtension->ClassDO = DriverExtension->MainClassDeviceObject;
 +      else
 +      {
 +              /* We need a new class device object for this Fdo */
 +              Status = CreateClassDeviceObject(
 +                      DriverObject,
 +                      &DeviceExtension->ClassDO);
 +              if (!NT_SUCCESS(Status))
 +              {
 +                      WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
 +                      goto cleanup;
 +              }
 +      }
 +      Status = ConnectPortDriver(Fdo, DeviceExtension->ClassDO);
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "ConnectPortDriver() failed with status 0x%08lx\n", Status);
 +              goto cleanup;
 +      }
 +      Fdo->Flags &= ~DO_DEVICE_INITIALIZING;
 + 
 +      /* Register interface ; ignore the error (if any) as having
 +       * a registred interface is not so important... */
 +      Status = IoRegisterDeviceInterface(
 +              Pdo,
 +              &GUID_DEVINTERFACE_KEYBOARD,
 +              NULL,
 +              &DeviceExtension->InterfaceName);
 +      if (!NT_SUCCESS(Status))
 +              DeviceExtension->InterfaceName.Length = 0;
 + 
 +      return STATUS_SUCCESS;
 + 
 + cleanup:
 +      if (Fdo)
 +              DestroyPortDriver(Fdo);
 +      return Status;
 + }
 + 
 + static VOID NTAPI
 + ClassCancelRoutine(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp)
 + {
 +      PCLASS_DEVICE_EXTENSION ClassDeviceExtension = DeviceObject->DeviceExtension;
 +      KIRQL OldIrql;
 +      BOOLEAN wasQueued = FALSE;
 + 
 +      TRACE_(CLASS_NAME, "ClassCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
 + 
 +      ASSERT(ClassDeviceExtension->Common.IsClassDO);
 + 
 +      IoReleaseCancelSpinLock(Irp->CancelIrql);
 + 
 +      KeAcquireSpinLock(&ClassDeviceExtension->SpinLock, &OldIrql);
 + 
 +      if (ClassDeviceExtension->PendingIrp == Irp)
 +      {
 +              ClassDeviceExtension->PendingIrp = NULL;
 +              wasQueued = TRUE;
 +      }
 +      KeReleaseSpinLock(&ClassDeviceExtension->SpinLock, OldIrql);
 + 
 +      if (wasQueued)
 +      {
 +              Irp->IoStatus.Status = STATUS_CANCELLED;
 +              Irp->IoStatus.Information = 0;
 +              IoCompleteRequest(Irp, IO_NO_INCREMENT);
 +      }
 +      else
 +      {
 +              /* Hm, this shouldn't happen */
 +              ASSERT(FALSE);
 +      }
 + }
 + 
 + static NTSTATUS
 + HandleReadIrp(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp,
 +      BOOLEAN IsInStartIo)
 + {
 +      PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
 +      NTSTATUS Status;
 +      KIRQL OldIrql;
 + 
 +      TRACE_(CLASS_NAME, "HandleReadIrp(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
 + 
 +      ASSERT(DeviceExtension->Common.IsClassDO);
 + 
 +      if (DeviceExtension->InputCount > 0)
 +      {
 +              SIZE_T NumberOfEntries;
 + 
 +              NumberOfEntries = MIN(
 +                      DeviceExtension->InputCount,
 +                      IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length / sizeof(KEYBOARD_INPUT_DATA));
 + 
 +              Status = FillEntries(
 +                      DeviceObject,
 +                      Irp,
 +                      DeviceExtension->PortData,
 +                      NumberOfEntries);
 + 
 +              if (NT_SUCCESS(Status))
 +              {
 +                      if (DeviceExtension->InputCount > NumberOfEntries)
 +                      {
 +                              RtlMoveMemory(
 +                                      &DeviceExtension->PortData[0],
 +                                      &DeviceExtension->PortData[NumberOfEntries],
 +                                      (DeviceExtension->InputCount - NumberOfEntries) * sizeof(KEYBOARD_INPUT_DATA));
 +                      }
 + 
 +                      DeviceExtension->InputCount -= NumberOfEntries;
 + 
 +                      Irp->IoStatus.Information = NumberOfEntries * sizeof(KEYBOARD_INPUT_DATA);
 +              }
 + 
 +              /* Go to next packet and complete this request */
 +              Irp->IoStatus.Status = Status;
 + 
 +              (VOID)IoSetCancelRoutine(Irp, NULL);
 +              IoCompleteRequest(Irp, IO_KEYBOARD_INCREMENT);
 +              DeviceExtension->PendingIrp = NULL;
 +      }
 +      else
 +      {
 +              IoAcquireCancelSpinLock(&OldIrql);
 +              if (Irp->Cancel)
 +              {
 +                      DeviceExtension->PendingIrp = NULL;
 +                      Status = STATUS_CANCELLED;
 +              }
 +              else
 +              {
 +                      IoMarkIrpPending(Irp);
 +                      DeviceExtension->PendingIrp = Irp;
 +                      (VOID)IoSetCancelRoutine(Irp, ClassCancelRoutine);
 +                      Status = STATUS_PENDING;
 +              }
 +              IoReleaseCancelSpinLock(OldIrql);
 +      }
 +      return Status;
 + }
 + 
++ static NTSTATUS NTAPI
++ ClassPnp(
++      IN PDEVICE_OBJECT DeviceObject,
++      IN PIRP Irp)
++ {
++      PPORT_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
++      PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
++      OBJECT_ATTRIBUTES ObjectAttributes;
++      IO_STATUS_BLOCK Iosb;
++      NTSTATUS Status;
++      
++      switch (IrpSp->MinorFunction)
++      {
++              case IRP_MN_START_DEVICE:
++                  Status = ForwardIrpAndWait(DeviceObject, Irp);
++                      if (NT_SUCCESS(Status))
++                      {
++                              InitializeObjectAttributes(&ObjectAttributes,
++                                                                                 &DeviceExtension->InterfaceName,
++                                                                                 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
++                                                                                 NULL,
++                                                                                 NULL);
++ 
++                              Status = ZwOpenFile(&DeviceExtension->FileHandle,
++                                                                      FILE_READ_DATA,
++                                                                      &ObjectAttributes,
++                                                                      &Iosb,
++                                                                      0,
++                                                                      0);
++                              if (!NT_SUCCESS(Status))
++                                      DeviceExtension->FileHandle = NULL;
++                      }
++                      else
++                              DeviceExtension->FileHandle = NULL;
++                      Irp->IoStatus.Status = Status;
++                      IoCompleteRequest(Irp, IO_NO_INCREMENT);
++                      return Status;
++                      
++              case IRP_MN_REMOVE_DEVICE:
++              case IRP_MN_STOP_DEVICE:
++                      if (DeviceExtension->FileHandle)
++                      {
++                              ZwClose(DeviceExtension->FileHandle);
++                              DeviceExtension->FileHandle = NULL;
++                      }
++                      Status = STATUS_SUCCESS;
++                      break;
++ 
++              default:
++                      Status = Irp->IoStatus.Status;
++                      break;
++      }
++ 
++      Irp->IoStatus.Status = Status;
++      if (NT_SUCCESS(Status) || Status == STATUS_NOT_SUPPORTED)
++      {
++              IoSkipCurrentIrpStackLocation(Irp);
++              return IoCallDriver(DeviceExtension->LowerDevice, Irp);
++      }
++      else
++      {
++              IoCompleteRequest(Irp, IO_NO_INCREMENT);
++              return Status;
++      }
++ }
++ 
 + static VOID NTAPI
 + ClassStartIo(
 +      IN PDEVICE_OBJECT DeviceObject,
 +      IN PIRP Irp)
 + {
 +      PCLASS_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension;
 +      KIRQL OldIrql;
 + 
 +      TRACE_(CLASS_NAME, "ClassStartIo(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
 + 
 +      ASSERT(DeviceExtension->Common.IsClassDO);
 + 
 +      KeAcquireSpinLock(&DeviceExtension->SpinLock, &OldIrql);
 +      HandleReadIrp(DeviceObject, Irp, TRUE);
 +      KeReleaseSpinLock(&DeviceExtension->SpinLock, OldIrql);
 + }
 + 
 + static VOID NTAPI
 + SearchForLegacyDrivers(
 +      IN PDRIVER_OBJECT DriverObject,
 +      IN PVOID Context, /* PCLASS_DRIVER_EXTENSION */
 +      IN ULONG Count)
 + {
 +      UNICODE_STRING DeviceMapKeyU = RTL_CONSTANT_STRING(L"\\REGISTRY\\MACHINE\\HARDWARE\\DEVICEMAP");
 +      PCLASS_DRIVER_EXTENSION DriverExtension;
 +      UNICODE_STRING PortBaseName = { 0, 0, NULL };
 +      PKEY_VALUE_BASIC_INFORMATION KeyValueInformation = NULL;
 +      OBJECT_ATTRIBUTES ObjectAttributes;
 +      HANDLE hDeviceMapKey = (HANDLE)-1;
 +      HANDLE hPortKey = (HANDLE)-1;
 +      ULONG Index = 0;
 +      ULONG Size, ResultLength;
 +      NTSTATUS Status;
 + 
 +      TRACE_(CLASS_NAME, "SearchForLegacyDrivers(%p %p %lu)\n",
 +              DriverObject, Context, Count);
 + 
 +      if (Count != 1)
 +              return;
 +      DriverExtension = (PCLASS_DRIVER_EXTENSION)Context;
 + 
 +      /* Create port base name, by replacing Class by Port at the end of the class base name */
 +      Status = DuplicateUnicodeString(
 +              RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
 +              &DriverExtension->DeviceBaseName,
 +              &PortBaseName);
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
 +              goto cleanup;
 +      }
 +      PortBaseName.Length -= (sizeof(L"Class") - sizeof(UNICODE_NULL));
 +      RtlAppendUnicodeToString(&PortBaseName, L"Port");
 + 
 +      /* Allocate memory */
 +      Size = sizeof(KEY_VALUE_BASIC_INFORMATION) + MAX_PATH;
 +      KeyValueInformation = ExAllocatePoolWithTag(PagedPool, Size, CLASS_TAG);
 +      if (!KeyValueInformation)
 +      {
 +              WARN_(CLASS_NAME, "ExAllocatePoolWithTag() failed\n");
 +              Status = STATUS_NO_MEMORY;
 +              goto cleanup;
 +      }
 + 
 +      /* Open HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP */
 +      InitializeObjectAttributes(&ObjectAttributes, &DeviceMapKeyU, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
 +      Status = ZwOpenKey(&hDeviceMapKey, 0, &ObjectAttributes);
 +      if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
 +      {
 +              INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP is non-existent\n");
 +              Status = STATUS_SUCCESS;
 +              goto cleanup;
 +      }
 +      else if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status);
 +              goto cleanup;
 +      }
 + 
 +      /* Open sub key */
 +      InitializeObjectAttributes(&ObjectAttributes, &PortBaseName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, hDeviceMapKey, NULL);
 +      Status = ZwOpenKey(&hPortKey, KEY_QUERY_VALUE, &ObjectAttributes);
 +      if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
 +      {
 +              INFO_(CLASS_NAME, "HKLM\\HARDWARE\\DEVICEMAP\\%wZ is non-existent\n", &PortBaseName);
 +              Status = STATUS_SUCCESS;
 +              goto cleanup;
 +      }
 +      else if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "ZwOpenKey() failed with status 0x%08lx\n", Status);
 +              goto cleanup;
 +      }
 + 
 +      /* Read each value name */
 +      while (ZwEnumerateValueKey(hPortKey, Index++, KeyValueBasicInformation, KeyValueInformation, Size, &ResultLength) == STATUS_SUCCESS)
 +      {
 +              UNICODE_STRING PortName;
 +              PDEVICE_OBJECT PortDeviceObject = NULL;
 +              PFILE_OBJECT FileObject = NULL;
 + 
 +              PortName.Length = PortName.MaximumLength = (USHORT)KeyValueInformation->NameLength;
 +              PortName.Buffer = KeyValueInformation->Name;
 + 
 +              /* Open the device object pointer */
 +              Status = IoGetDeviceObjectPointer(&PortName, FILE_READ_ATTRIBUTES, &FileObject, &PortDeviceObject);
 +              if (!NT_SUCCESS(Status))
 +              {
 +                      WARN_(CLASS_NAME, "IoGetDeviceObjectPointer(%wZ) failed with status 0x%08lx\n", &PortName, Status);
 +                      continue;
 +              }
 +              INFO_(CLASS_NAME, "Legacy driver found\n");
 + 
 +              Status = ClassAddDevice(DriverObject, PortDeviceObject);
 +              if (!NT_SUCCESS(Status))
 +              {
 +                      /* FIXME: Log the error */
 +                      WARN_(CLASS_NAME, "ClassAddDevice() failed with status 0x%08lx\n", Status);
 +              }
 + 
 +              /* A special hack for 1st stage setup: manually send start device to i8042prt */
 +              if (IsFirstStageSetup())
 +                      Send8042StartDevice(DriverObject, PortDeviceObject);
 +      }
 + 
 + cleanup:
 +      if (KeyValueInformation != NULL)
 +              ExFreePoolWithTag(KeyValueInformation, CLASS_TAG);
 +      if (hDeviceMapKey != (HANDLE)-1)
 +              ZwClose(hDeviceMapKey);
 +      if (hPortKey != (HANDLE)-1)
 +              ZwClose(hPortKey);
 + }
 + 
 + /*
 +  * Standard DriverEntry method.
 +  */
 + NTSTATUS NTAPI
 + DriverEntry(
 +      IN PDRIVER_OBJECT DriverObject,
 +      IN PUNICODE_STRING RegistryPath)
 + {
 +      PCLASS_DRIVER_EXTENSION DriverExtension;
 +      ULONG i;
 +      NTSTATUS Status;
 + 
 +      Status = IoAllocateDriverObjectExtension(
 +              DriverObject,
 +              DriverObject,
 +              sizeof(CLASS_DRIVER_EXTENSION),
 +              (PVOID*)&DriverExtension);
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "IoAllocateDriverObjectExtension() failed with status 0x%08lx\n", Status);
 +              return Status;
 +      }
 +      RtlZeroMemory(DriverExtension, sizeof(CLASS_DRIVER_EXTENSION));
 + 
 +      Status = DuplicateUnicodeString(
 +              RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
 +              RegistryPath,
 +              &DriverExtension->RegistryPath);
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "DuplicateUnicodeString() failed with status 0x%08lx\n", Status);
 +              return Status;
 +      }
 + 
 +      Status = ReadRegistryEntries(RegistryPath, DriverExtension);
 +      if (!NT_SUCCESS(Status))
 +      {
 +              WARN_(CLASS_NAME, "ReadRegistryEntries() failed with status 0x%08lx\n", Status);
 +              return Status;
 +      }
 + 
 +      if (DriverExtension->ConnectMultiplePorts == 1)
 +      {
 +              Status = CreateClassDeviceObject(
 +                      DriverObject,
 +                      &DriverExtension->MainClassDeviceObject);
 +              if (!NT_SUCCESS(Status))
 +              {
 +                      WARN_(CLASS_NAME, "CreateClassDeviceObject() failed with status 0x%08lx\n", Status);
 +                      return Status;
 +              }
 +      }
 + 
 +      DriverObject->DriverExtension->AddDevice = ClassAddDevice;
 +      DriverObject->DriverUnload = DriverUnload;
 + 
 +      for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
 +              DriverObject->MajorFunction[i] = IrpStub;
 + 
 +      DriverObject->MajorFunction[IRP_MJ_CREATE]         = ClassCreate;
 +      DriverObject->MajorFunction[IRP_MJ_CLOSE]          = ClassClose;
 +      DriverObject->MajorFunction[IRP_MJ_CLEANUP]        = ClassCleanup;
 +      DriverObject->MajorFunction[IRP_MJ_READ]           = ClassRead;
++      DriverObject->MajorFunction[IRP_MJ_PNP]            = ClassPnp;
 +      DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ClassDeviceControl;
 +      DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = ForwardIrpAndForget;
 +      DriverObject->DriverStartIo                        = ClassStartIo;
 + 
 +      /* We will detect the legacy devices later */
 +      IoRegisterDriverReinitialization(
 +              DriverObject,
 +              SearchForLegacyDrivers,
 +              DriverExtension);
 + 
 +      return STATUS_SUCCESS;
 + }
index 6026874,0000000,e6528c0..e6528c0
mode 100644,000000,100644..100644
--- /dev/null
@@@@ -1,4839 -1,0 -1,5122 +1,5122 @@@@
-      ULONG           portNumber = 0;
 + /*
 +  * PROJECT:         ReactOS Storage Stack
 +  * LICENSE:         DDK - see license.txt in the root dir
 +  * FILE:            drivers/storage/class2/class2.c
 +  * PURPOSE:         SCSI Class driver routines
 +  * PROGRAMMERS:     Based on a source code sample from Microsoft NT4 DDK
 +  */
 + 
 + #include <ntddk.h>
 + #include <ntdddisk.h>
 + #include <scsi.h>
 + #include <include/class2.h>
 + #include <stdio.h>
 + 
++ /* Part of the drive letter hack */
++ #include <ntifs.h>
++ #include <ketypes.h>
++ 
 + //#define NDEBUG
 + #include <debug.h>
 + 
 + #ifdef ALLOC_PRAGMA
 + #pragma alloc_text(PAGE, ScsiClassGetInquiryData)
 + #pragma alloc_text(PAGE, ScsiClassInitialize)
 + #pragma alloc_text(PAGE, ScsiClassGetCapabilities)
 + #pragma alloc_text(PAGE, ScsiClassSendSrbSynchronous)
 + #pragma alloc_text(PAGE, ScsiClassClaimDevice)
 + #pragma alloc_text(PAGE, ScsiClassSendSrbAsynchronous)
 + #endif
 + 
 + 
 + #define INQUIRY_DATA_SIZE 2048
 + #define START_UNIT_TIMEOUT  30
 + 
 + /* Disk layout used by Windows NT4 and earlier versions. */
 + //#define DEFAULT_SECTORS_PER_TRACK    32
 + //#define DEFAULT_TRACKS_PER_CYLINDER  64
 + 
 + /* Disk layout used by Windows 2000 and later versions. */
 + #define DEFAULT_SECTORS_PER_TRACK    63
 + #define DEFAULT_TRACKS_PER_CYLINDER 255
 + 
 + NTSTATUS
 + NTAPI
 + ScsiClassCreateClose(
 +     IN PDEVICE_OBJECT DeviceObject,
 +     IN PIRP Irp
 +     );
 + 
 + NTSTATUS
 + NTAPI
 + ScsiClassReadWrite(
 +     IN PDEVICE_OBJECT DeviceObject,
 +     IN PIRP Irp
 +     );
 + 
 + NTSTATUS
 + NTAPI
 + ScsiClassDeviceControlDispatch(
 +     PDEVICE_OBJECT DeviceObject,
 +     PIRP Irp
 +     );
 + 
 + NTSTATUS
 + NTAPI
 + ScsiClassDeviceControl(
 +     PDEVICE_OBJECT DeviceObject,
 +     PIRP Irp
 +     );
 + 
 + NTSTATUS
 + NTAPI
 + ScsiClassInternalIoControl (
 +     IN PDEVICE_OBJECT DeviceObject,
 +     IN PIRP Irp
 +     );
 + 
 + NTSTATUS
 + NTAPI
 + ScsiClassShutdownFlush(
 +     IN PDEVICE_OBJECT DeviceObject,
 +     IN PIRP Irp
 +     );
 + 
 + NTSTATUS
 + NTAPI
 + DriverEntry(
 +     IN PDRIVER_OBJECT DriverObject,
 +     IN PUNICODE_STRING RegistryPath
 +     );
 + 
 + //
 + // Class internal routines
 + //
 + 
 + 
 + VOID
 + NTAPI
 + RetryRequest(
 +     PDEVICE_OBJECT DeviceObject,
 +     PIRP Irp,
 +     PSCSI_REQUEST_BLOCK Srb,
 +     BOOLEAN Associated
 +     );
 + 
 + VOID
 + NTAPI
 + StartUnit(
 +     IN PDEVICE_OBJECT DeviceObject
 +     );
 + 
 + NTSTATUS
 + NTAPI
 + ClassIoCompletion(
 +     IN PDEVICE_OBJECT DeviceObject,
 +     IN PIRP Irp,
 +     IN PVOID Context
 +     );
 + 
 + NTSTATUS
 + NTAPI
 + ClassCompletionRoutine(IN PDEVICE_OBJECT DeviceObject,
 +                        IN PIRP Irp,
 +                        IN PVOID Context);
 + 
 + 
 + NTSTATUS
 + NTAPI
 + DriverEntry(
 +     IN PDRIVER_OBJECT DriverObject,
 +     IN PUNICODE_STRING RegistryPath
 +     )
 + {
 +     return STATUS_SUCCESS;
 + }
 + 
++ /* The following hack to assign drive letters with a non-PnP storage stack */
++ 
++ typedef struct _CLASS_DEVICE_INFO {
++   ULONG Partitions;
++   ULONG DeviceNumber;
++   ULONG DriveNumber;
++   PDEVICE_OBJECT LowerDevice;
++ } CLASS_DEVICE_INFO, *PCLASS_DEVICE_INFO;
++ 
++ typedef struct _CLASS_DRIVER_EXTENSION {
++   ULONG PortNumber;
++   CLASS_INIT_DATA InitializationData;
++ } CLASS_DRIVER_EXTENSION, *PCLASS_DRIVER_EXTENSION;
++ 
++ VOID
++ NTAPI
++ ScsiClassRemoveDriveLetter(PCLASS_DEVICE_INFO DeviceInfo)
++ {
++     WCHAR Buffer1[100];
++     UNICODE_STRING DriveLetterU;
++     ULONG Index;
++ 
++     DriveLetterU.Buffer = Buffer1;
++     DriveLetterU.MaximumLength = sizeof(Buffer1);
++ 
++     /* Delete the symbolic link to PhysicalDriveX */
++     DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\PhysicalDrive%d", DeviceInfo->DriveNumber) * sizeof(WCHAR);
++     IoDeleteSymbolicLink(&DriveLetterU);
++ 
++     DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU);
++ 
++     for (Index = 0; Index < sizeof(ULONG) * 8; Index++)
++     {
++         if (DeviceInfo->Partitions & (1 << Index))
++         {
++             DriveLetterU.Length = swprintf(DriveLetterU.Buffer, L"\\??\\%C:", ('C' + Index)) * sizeof(WCHAR);
++             IoDeleteSymbolicLink(&DriveLetterU);
++             DbgPrint("HACK: Deleted symbolic link %wZ\n", &DriveLetterU);
++         }
++     }
++ }
++ 
++ NTSTATUS
++ NTAPI
++ ScsiClassAssignDriveLetter(PCLASS_DEVICE_INFO DeviceInfo)
++ {
++     WCHAR Buffer1[100];
++     WCHAR Buffer2[100];
++     UNICODE_STRING DriveLetterU, PartitionU;
++     NTSTATUS Status;
++     ULONG Index, PartitionNumber, DeviceNumber, DriveNumber;
++     OBJECT_ATTRIBUTES ObjectAttributes;
++     IO_STATUS_BLOCK Iosb;
++     HANDLE PartitionHandle;
++ 
++     /* We assume this device does not current have a drive letter */
++ 
++     Index = 0;
++     DeviceNumber = 0;
++     DriveNumber = 0;
++     PartitionNumber = 1;
++     DriveLetterU.Buffer = Buffer1;
++     DriveLetterU.MaximumLength = sizeof(Buffer1);
++     PartitionU.Buffer = Buffer2;
++     PartitionU.MaximumLength = sizeof(Buffer2);
++ 
++     /* Determine the correct disk number */
++     do
++     {
++         /* Check that the disk exists */
++         PartitionU.Length = swprintf(PartitionU.Buffer, L"\\Device\\HardDisk%d\\Partition0", DeviceNumber) * sizeof(WCHAR);
++         InitializeObjectAttributes(&ObjectAttributes,
++                                    &PartitionU,
++                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
++                                    NULL,
++                                    NULL);
++         Status = ZwOpenFile(&PartitionHandle,
++                             FILE_READ_ATTRIBUTES,
++                             &ObjectAttributes,
++                             &Iosb,
++                             0,
++                             0);
++         if (!NT_SUCCESS(Status))
++         {
++             /* Return the last one that worked */
++             DeviceNumber--;
++         }
++         else
++         {
++             ZwClose(PartitionHandle);
++             DeviceNumber++;
++         }
++     } while (Status == STATUS_SUCCESS);
++ 
++     /* Determine the correct drive number */
++     do
++     {
++         /* Check that the drive exists */
++         PartitionU.Length = swprintf(PartitionU.Buffer, L"\\??\\PhysicalDrive%d", DriveNumber) * sizeof(WCHAR);
++         InitializeObjectAttributes(&ObjectAttributes,
++                                    &PartitionU,
++                                    OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
++                                    NULL,
++                                    NULL);
++         Status = ZwOpenFile(&PartitionHandle,
++