#!/bin/sh # # Copyright (c) 2005 # Bill Paul . All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # 3. All advertising materials mentioning features or use of this software # must display the following acknowledgement: # This product includes software developed by Bill Paul. # 4. Neither the name of the author nor the names of any co-contributors # may be used to endorse or promote products derived from this software # without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF # THE POSSIBILITY OF SUCH DAMAGE. # # $FreeBSD: stable/11/usr.sbin/ndiscvt/ndisgen.sh 297434 2016-03-30 23:50:23Z bdrewery $ # proc header { clear echo " ==================================================================" echo " ------------------ Windows(r) driver converter -------------------" echo " ==================================================================" echo "" } proc mainmenu { header echo " This script is designed to guide you through the process" echo " of converting a Windows(r) binary driver module and .INF" echo " specification file into a FreeBSD ELF kernel module for use" echo " with the NDIS compatibility system." echo "" echo " The following options are available:" echo "" echo " 1] Learn about the NDIS compatibility system" echo " 2] Convert individual firmware files" echo " 3] Convert driver" echo " 4] Exit" echo "" echo -n " Enter your selection here and press return: " read KEYPRESS return } proc help1 { header echo " General information" echo "" echo " The NDIS compatibility system is designed to let you use Windows(r)" echo " binary drivers for networking devices with FreeBSD, in cases where" echo " a native FreeBSD driver is not available due to hardware manufacturer" echo " oversight or stupidity. NDIS stands for Network Driver Interface" echo " Standard, and refers to the programming model used to write Windows(r)" echo " network drivers. (These are often called \"NDIS miniport\" drivers.)" echo "" echo " In order to use your network device in NDIS compatibility mode," echo " you need the Windows(r) driver that goes with it. Also, the driver" echo " must be compiled for the same architecture as the release of FreeBSD" echo " you have installed. At this time, the i386 and amd64 architectures" echo " are both supported. Note that you cannot use a Windows/i386 driver" echo " with FreeBSD/amd64: you must obtain a Windows/amd64 driver." echo "" echo -n " Press return to continue... " read KEYPRESS return } proc help2 { header echo " Where to get drivers" echo "" echo " If you purchased your network card separately from your computer," echo " there should have been a driver distribution CD included with the" echo " card which contains Windows(r) drivers. The NDIS compatibility" echo " system is designed to emulate the NDIS API of a couple of different" echo " Windows(r) releases, however it works best with drivers designed" echo " for NDIS 5.0 or later. Drivers distributed for Windows 2000 should" echo " work; however, for best results you should use a driver designed" echo " for Windows XP or Windows Server 2003." echo "" echo " If your card was supplied with your computer, or is a built-in device," echo " drivers may have been included on a special driver bundle CD shipped" echo " with the computer." echo "" echo " If you don't have a driver CD, you should be able to find a driver" echo " kit on the card or computer vendor's web site." echo "" echo -n " Press return to continue... " read KEYPRESS return } proc help3 { header echo " What files do I need?" echo "" echo " In most cases, you will need only two files: a .INF file and a .SYS" echo " file. The .INF file is a text file used by the Windows(r) installer to" echo " perform the driver installation. It contains information that tells" echo " the installer what devices the driver supports and what registry keys" echo " should be created to control driver configuration. The .SYS file" echo " is the actual driver executable code in Windows(r) Portable Executable" echo " (PE) format. Note that sometimes the .INF file is supplied in Unicode" echo " format. Unicode .INF files must be converted to ASCII form with the" echo " iconv(1) utility before this installer script can use them." echo " Occasionally, a driver may require firmware or register setup" echo " files that are external to the main .SYS file. These are provided" echo " on the same CD with the driver itself, and sometimes have a .BIN" echo " extension, though they can be named almost anything. You will need" echo " these additional files to make your device work with the NDIS" echo " compatibility system as well." echo "" echo -n " Press return to continue... " read KEYPRESS return } proc help4 { header echo " How does it all work?" echo "" echo " The installer script uses the ndiscvt(1) utility to convert the .INF," echo " .SYS and optional firmware files into a FreeBSD kernel loadable module" echo " (.ko) file. This module can be loaded via the kldload(8) utility or" echo " loaded automatically via the /boot/loader.conf file. The ndiscvt(1)" echo " utility extracts the device ID information and registry key data" echo " from the .INF file and converts it into a C header file. It also uses" echo " the objcopy(1) utility to convert the .SYS file and optional firmware" echo " files into ELF objects. The header file is compiled into a small C" echo " stub file which contains a small amount of code to interface with" echo " the FreeBSD module system. This stub is linked together with the" echo " converted ELF objects to form a FreeBSD kernel module. A static ELF" echo " object (.o) file is also created. This file can be linked into a" echo " static kernel image for those who want/need a fully linked kernel" echo " image (possibly for embedded bootstrap purposes, or just plain old" echo " experimentation)." echo "" echo -n " Press return to continue... " read KEYPRESS return } proc help5 { header echo " Prerequisites" echo "" echo " Converting a driver requires the following utilities:" echo "" echo " - The FreeBSD C compiler, cc(1) (part of the base install)." echo " - The FreeBSD linker, ld(1) (part of the base install)." echo " - The objcopy(1) utility (part of the base install)." echo " - The ndiscvt(1) utility (part of the base install)." echo "" echo " If you happen to end up with a .INF file that's in Unicode format," echo " then you'll also need:" echo "" echo " - The iconv(1) utility." echo "" echo " If you have installed the X Window system or some sort of desktop" echo " environment, then iconv(1) should already be present. If not, you" echo " will need to install the libiconv package or port." echo "" echo -n " Press return to continue... " read KEYPRESS return } proc infconv { header echo " INF file validation" if test -z $INFPATH { echo "" echo "" echo " A .INF file is most often provided as an ASCII file, however" echo " files with multilanguage support are provided in Unicode format." echo " Please type in the path to your .INF file now." echo "" echo -n " > " read INFPATH } if test $(INFPATH) && test -e $(INFPATH) { setglobal INFTYPE = $[$(EGREP) -i -c "Signature|.S.i.g.n.a.t.u.r.e" $(INFPATH)] if test $(INFTYPE) -le 0 { echo "" echo " I don't recognize this file format. It may not be a valid .INF file." echo "" echo -n " Press enter to try again, or ^C to quit. " read KEYPRESS setglobal INFPATH = ''"" return } setglobal INFTYPE = $[$(EGREP) -i -c "Class.*=.*Net" $(INFPATH)] if test $(INFTYPE) -gt 0 { echo "" echo " This .INF file appears to be ASCII." echo "" echo -n " Press return to continue... " read KEYPRESS return } setglobal INFTYPE = $[$(EGREP) -i -c ".C.l.a.s.s.*=.*N.e.t" $(INFPATH)] if test $(INFTYPE) -gt 0 { echo "" echo " This .INF file appears to be Unicode." if test -e $(ICONVPATH) { echo " Trying to convert to ASCII..." $(ICONVPATH) -f utf-16 -t utf-8 $(INFPATH) > $(INFFILE) setglobal INFPATH = $(INFFILE) echo " Done." echo "" echo -n " Press return to continue... " read KEYPRESS } else { echo " The iconv(1) utility does not appear to be installed." echo " Please install this utility or convert the .INF file" echo " to ASCII and run this utility again." echo "" exit } return } echo "" echo " I don't recognize this file format. It may not be a valid .INF file." echo "" echo -n " Press enter to try again, or ^C to quit. " read KEYPRESS setglobal INFPATH = ''"" } else { echo "" echo " The file '$(INFPATH)' was not found." echo "" echo -n " Press enter to try again, or ^C to quit. " read KEYPRESS setglobal INFPATH = ''"" } return } proc sysconv { header echo " Driver file validation" if test ! -r $SYSPATH { echo "" echo "" echo " Now you need to specify the name of the Windows(r) driver .SYS" echo " file for your device. Note that if you are running FreeBSD/amd64," echo " then you must provide a driver that has been compiled for the" echo " 64-bit Windows(r) platform. If a 64-bit driver is not available" echo " for your device, you must install FreeBSD/i386 and use the" echo " 32-bit driver instead." echo "" echo " Please type in the path to the Windows(r) driver .SYS file now." echo "" echo -n " > " read SYSPATH } if test $(SYSPATH) && test -e $(SYSPATH) { setglobal SYSTYPE = $[$(FILE) $(SYSPATH)] match $(SYSTYPE) { with *Windows* echo "" echo " This .SYS file appears to be in Windows(r) PE format." echo "" echo -n " Press return to continue... " read KEYPRESS setglobal SYSBASE = $[$(BASENAME) $(SYSPATH) | $(TR) '.' '_] with * echo "" echo " I don't recognize this file format. It may not be a valid .SYS file." echo "" echo -n " Press enter to try again, or ^C to quit. " read KEYPRESS setglobal SYSPATH = ''"" } } else { echo "" echo " The file '$(SYSPATH)' was not found." echo "" echo -n " Press enter to try again, or ^C to quit. " read KEYPRESS setglobal SYSPATH = ''"" } return } proc ndiscvt { header echo " Driver file conversion" echo "" echo " The script will now try to convert the .INF and .SYS files" echo " using the ndiscvt(1) utility. This utility can handle most" echo " .INF files; however, occasionally it can fail to parse some files" echo " due to subtle syntax issues: the .INF syntax is very complex," echo " and the Windows(r) parser will sometimes allow files with small" echo " syntax errors to be processed correctly which ndiscvt(1) will" echo " not. If the conversion fails, you may have to edit the .INF" echo " file by hand to remove the offending lines." echo "" echo -n " Press enter to try converting the files now: " read KEYPRESS if ! $(NDISCVT) -i $(INFPATH) -s $(SYSPATH) -O -o $(DNAME).h > /dev/null { echo "CONVERSION FAILED" exit } else { echo "" echo " Conversion was successful." echo "" echo -n " Press enter to continue... " read KEYPRESS } return } proc firmcvt { while : { header echo " Firmware file conversion" echo "" echo " If your driver uses additional firmware files, please list them" echo " below. When you're finished, just press enter to continue. (If your" echo " driver doesn't need any extra firmware files, just press enter" echo " to move to the next step.)" echo "" echo -n " > " read FIRMPATH if test $(FIRMPATH) { if test ! -e $(FIRMPATH) { echo "" echo " The file '$(FIRMPATH)' was not found" echo "" echo -n " Press enter to try again, or ^C to quit. " read KEYPRESS continue } if ! $(NDISCVT) -f $(FIRMPATH) > /dev/null { echo "" echo "CONVERSION FAILED" } else { echo "" echo " Conversion was successful." echo "" setglobal FRMBASE = $[$(BASENAME) $(FIRMPATH)] setglobal FRMBASE = ""$(FRMBASE).o"" setglobal FRMLIST = ""$(FRMLIST) $(FRMBASE)"" } echo -n " Press enter to continue... " read KEYPRESS } else { break } } header echo "" echo " List of files converted firmware files:" echo "" for i in [$(FRMLIST)] { echo " "$i } echo "" echo -n " Press enter to continue... " read KEYPRESS return } proc drvgen { header echo " Kernel module generation" echo "" echo "" echo " The script will now try to generate the kernel driver module." echo " This is the last step. Once this module is generated, you should" echo " be able to load it just like any other FreeBSD driver module." echo "" echo " Press enter to compile the stub module and generate the driver" echo -n " module now: " read KEYPRESS echo "" echo -n " Generating Makefile... " echo ".PATH: $(PWD) $(STUBPATH)" > $(MAKEFILE) echo "KMOD= $(SYSBASE)" >> $(MAKEFILE) echo "SRCS+= $(STUBFILE) $(DNAME).h bus_if.h device_if.h" >> $(MAKEFILE) echo "OBJS+=$(FRMLIST) $(DNAME).o" >> $(MAKEFILE) echo "CFLAGS+= \\" >> $(MAKEFILE) echo " -DDRV_DATA_START=ndis_$(SYSBASE)_drv_data_start \\" >> $(MAKEFILE) echo " -DDRV_NAME=ndis_$(SYSBASE) \\" >> $(MAKEFILE) echo " -DDRV_DATA_END=ndis_$(SYSBASE)_drv_data_end" >> $(MAKEFILE) echo "CLEANFILES+= \\" >> $(MAKEFILE) echo " $(INFFILE) \\" >> $(MAKEFILE) echo " $(DNAME).h \\" >> $(MAKEFILE) echo " $(DNAME).o" >> $(MAKEFILE) echo ".include " >> $(MAKEFILE) if test -f $(MAKEFILE) { echo "done." } else { echo "generating Makefile failed. Exiting." echo "" exit } echo -n " Building kernel module... " echo "" > bus_if.h echo "" > device_if.h if ! $(MAKE) -f $(MAKEFILE) all > /dev/null { echo "build failed. Exiting." echo "" exit } else { if test -f $(SYSBASE).ko { $(MV) $(SYSBASE).ko $(SYSBASE).kmod echo "done." } else { echo "build failed. Exiting." echo "" exit } } echo -n " Cleaning up... " if ! $(MAKE) -f $(MAKEFILE) clean cleandepend > /dev/null { echo "cleanup failed. Exiting." echo "" exit } else { echo "done." } $(RM) $(MAKEFILE) $(MV) $(SYSBASE).kmod $(SYSBASE).ko echo "" echo " The file $(SYSBASE).ko has been successfully generated." echo " You can kldload this module to get started." echo "" echo -n " Press return to exit. " read KEYPRESS echo "" echo "" return } proc convert_driver { while : { infconv if test $(INFPATH) { break } } while : { sysconv if test $(SYSPATH) { break } } ndiscvt firmcvt drvgen return } setglobal ICONVPATH = '/usr/bin/iconv' setglobal NDISCVT = '/usr/sbin/ndiscvt' setglobal STUBPATH = '/usr/share/misc' setglobal STUBFILE = 'windrv_stub.c' setglobal DNAME = 'windrv' setglobal CP = '/bin/cp' setglobal MV = '/bin/mv' setglobal RM = '/bin/rm' setglobal TR = '/usr/bin/tr' setglobal FILE = '/usr/bin/file' setglobal EGREP = '/usr/bin/egrep' setglobal MAKE = '/usr/bin/make' setglobal BASENAME = '/usr/bin/basename' setglobal TOUCH = '/usr/bin/touch' setglobal MKTEMP = '/usr/bin/mktemp' setglobal MAKEFILE = $[$(MKTEMP) /tmp/Makefile.XXXXXX] setglobal INFFILE = $[$(MKTEMP) /tmp/ascii_inf.XXXXXX] setglobal INFPATH = ''"" setglobal FRMLIST = ''"" setglobal SYSPATH = ''"" setglobal SYSBASE = ''"" setglobal FRMBASE = ''"" if test -r $1 -a -r $2 { # Looks like the user supplied .INF and .SYS files on the command line setglobal INFPATH = $1 setglobal SYSPATH = $2 convert_driver && exit 0 } while : { mainmenu match $(KEYPRESS) { with 1 help1 help2 help3 help4 help5 with 2 firmcvt with 3 convert_driver with 4 header echo "" echo " Be seeing you!" echo "" exit with * header echo "" echo -n " Sorry, I didn't understand that. Press enter to try again: " read KEYPRESS } } exit