1#!/bin/sh
2#
3# SPDX-License-Identifier: BSD-4-Clause
4#
5# Copyright (c) 2005
6#	Bill Paul <wpaul@windriver.com>.  All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16# 3. All advertising materials mentioning features or use of this software
17#    must display the following acknowledgement:
18#	This product includes software developed by Bill Paul.
19# 4. Neither the name of the author nor the names of any co-contributors
20#    may be used to endorse or promote products derived from this software
21#    without specific prior written permission.
22#
23# THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
24# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26# ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
27# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33# THE POSSIBILITY OF SUCH DAMAGE.
34#
35# $FreeBSD$
36#
37
38header () {
39clear
40echo "	=================================================================="
41echo "	------------------ Windows(r) driver converter -------------------"
42echo "	=================================================================="
43echo ""
44}
45
46mainmenu() {
47header
48echo "	This script is designed to guide you through the process"
49echo "	of converting a Windows(r) binary driver module and .INF"
50echo "	specification file into a FreeBSD ELF kernel module for use"
51echo "	with the NDIS compatibility system."
52echo ""
53echo "	The following options are available:"
54echo ""
55echo "	1] Learn about the NDIS compatibility system"
56echo "	2] Convert individual firmware files"
57echo "	3] Convert driver"
58echo "	4] Exit"
59echo ""
60echo -n "	Enter your selection here and press return: "
61read KEYPRESS
62return
63}
64
65
66help1 () {
67header
68echo "				General information"
69echo ""
70echo "	The NDIS compatibility system is designed to let you use Windows(r)"
71echo "	binary drivers for networking devices with FreeBSD, in cases where"
72echo "	a native FreeBSD driver is not available due to hardware manufacturer"
73echo "	oversight or stupidity. NDIS stands for Network Driver Interface"
74echo "	Standard, and refers to the programming model used to write Windows(r)"
75echo "	network drivers. (These are often called \"NDIS miniport\" drivers.)"
76echo ""
77echo "	In order to use your network device in NDIS compatibility mode,"
78echo "	you need the Windows(r) driver that goes with it. Also, the driver"
79echo "	must be compiled for the same architecture as the release of FreeBSD"
80echo "	you have installed. At this time, the i386 and amd64 architectures"
81echo "	are both supported. Note that you cannot use a Windows/i386 driver"
82echo "	with FreeBSD/amd64: you must obtain a Windows/amd64 driver."
83echo ""
84echo -n "	Press return to continue... "
85read KEYPRESS
86return
87}
88
89help2() {
90header
91echo "				Where to get drivers"
92echo ""
93echo "	If you purchased your network card separately from your computer,"
94echo "	there should have been a driver distribution CD included with the"
95echo "	card which contains Windows(r) drivers. The NDIS compatibility"
96echo "	system is designed to emulate the NDIS API of a couple of different"
97echo "	Windows(r) releases, however it works best with drivers designed"
98echo "	for NDIS 5.0 or later. Drivers distributed for Windows 2000 should"
99echo "	work; however, for best results you should use a driver designed"
100echo "	for Windows XP or Windows Server 2003."
101echo ""
102echo "	If your card was supplied with your computer, or is a built-in device,"
103echo "	drivers may have been included on a special driver bundle CD shipped"
104echo "	with the computer."
105echo ""
106echo "	If you don't have a driver CD, you should be able to find a driver"
107echo "	kit on the card or computer vendor's web site."
108echo ""
109echo -n "	Press return to continue... "
110read KEYPRESS
111return
112}
113
114help3 () {
115header
116echo "				What files do I need?"
117echo ""
118echo "	In most cases, you will need only two files: a .INF file and a .SYS"
119echo "	file. The .INF file is a text file used by the Windows(r) installer to"
120echo "	perform the driver installation. It contains information that tells"
121echo "	the installer what devices the driver supports and what registry keys"
122echo "	should be created to control driver configuration. The .SYS file"
123echo "	is the actual driver executable code in Windows(r) Portable Executable"
124echo "	(PE) format. Note that sometimes the .INF file is supplied in Unicode"
125echo "	format. Unicode .INF files must be converted to ASCII form with the"
126echo "	iconv(1) utility before this installer script can use them."
127echo "	Occasionally, a driver may require firmware or register setup"
128echo "	files that are external to the main .SYS file. These are provided"
129echo "	on the same CD with the driver itself, and sometimes have a .BIN"
130echo "	extension, though they can be named almost anything. You will need"
131echo "	these additional files to make your device work with the NDIS"
132echo "	compatibility system as well."
133echo ""
134echo -n "	Press return to continue... "
135read KEYPRESS
136return
137}
138
139help4 () {
140header
141echo "				How does it all work?"
142echo ""
143echo "	The installer script uses the ndiscvt(1) utility to convert the .INF,"
144echo "	.SYS and optional firmware files into a FreeBSD kernel loadable module"
145echo "	(.ko) file. This module can be loaded via the kldload(8) utility or"
146echo "	loaded automatically via the /boot/loader.conf file. The ndiscvt(1)"
147echo "	utility extracts the device ID information and registry key data"
148echo "	from the .INF file and converts it into a C header file. It also uses"
149echo "	the objcopy(1) utility to convert the .SYS file and optional firmware"
150echo "	files into ELF objects. The header file is compiled into a small C"
151echo "	stub file which contains a small amount of code to interface with"
152echo "	the FreeBSD module system. This stub is linked together with the"
153echo "	converted ELF objects to form a FreeBSD kernel module. A static ELF"
154echo "	object (.o) file is also created. This file can be linked into a"
155echo "	static kernel image for those who want/need a fully linked kernel"
156echo "	image (possibly for embedded bootstrap purposes, or just plain old"
157echo "	experimentation)."
158echo ""
159echo -n "	Press return to continue... "
160read KEYPRESS
161return
162}
163
164help5 () {
165header
166echo "				Prerequisites"
167echo ""
168echo "	Converting a driver requires the following utilities:"
169echo ""
170echo "	- The FreeBSD C compiler, cc(1) (part of the base install)."
171echo "	- The FreeBSD linker, ld(1) (part of the base install)."
172echo "	- The objcopy(1) utility (part of the base install)."
173echo "	- The ndiscvt(1) utility (part of the base install)."
174echo ""
175echo "	If you happen to end up with a .INF file that's in Unicode format,"
176echo "	then you'll also need:"
177echo ""
178echo "	- The iconv(1) utility."
179echo ""
180echo "	If you have installed the X Window system or some sort of desktop"
181echo "	environment, then iconv(1) should already be present. If not, you"
182echo "	will need to install the libiconv package or port."
183echo ""
184echo -n "	Press return to continue... "
185read KEYPRESS
186return
187}
188
189infconv () {
190header
191echo "			INF file validation"
192
193if [ -z "$INFPATH" ]; then
194	echo ""
195	echo ""
196	echo "	A .INF file is most often provided as an ASCII file, however"
197	echo "	files with multilanguage support are provided in Unicode format."
198	echo "	Please type in the path to your .INF file now."
199	echo ""
200	echo -n "	> "
201	read INFPATH
202fi
203
204if [ ${INFPATH} ] && [ -e ${INFPATH} ]; then 
205	INFTYPE=`${EGREP} -i -c "Signature|.S.i.g.n.a.t.u.r.e" ${INFPATH}`
206	if [ ${INFTYPE} -le 0 ]; then
207		echo ""
208		echo "	I don't recognize this file format. It may not be a valid .INF file."
209		echo ""
210		echo -n "	Press enter to try again, or ^C to quit. "
211		read KEYPRESS
212		INFPATH=""
213		return
214	fi
215
216	INFTYPE=`${EGREP} -i -c "Class.*=.*Net" ${INFPATH}`
217	if [ ${INFTYPE} -gt 0 ]; then
218		echo ""
219		echo "	This .INF file appears to be ASCII."
220		echo ""
221		echo -n "	Press return to continue... "
222		read KEYPRESS
223		return
224	fi
225
226	INFTYPE=`${EGREP} -i -c ".C.l.a.s.s.*=.*N.e.t" ${INFPATH}`
227	if [ ${INFTYPE} -gt 0 ]; then
228		echo ""
229		echo "	This .INF file appears to be Unicode."
230		if [ -e ${ICONVPATH} ]; then
231			echo "	Trying to convert to ASCII..."
232			${ICONVPATH} -f utf-16 -t utf-8 ${INFPATH} > ${INFFILE}
233			INFPATH=${INFFILE}
234			echo "	Done."
235			echo ""
236			echo -n "	Press return to continue... "
237			read KEYPRESS
238		else
239			echo "	The iconv(1) utility does not appear to be installed."
240			echo "	Please install this utility or convert the .INF file"
241			echo "	to ASCII and run this utility again."
242			echo ""
243			exit
244		fi
245		return
246	fi
247
248	echo ""
249	echo "	I don't recognize this file format. It may not be a valid .INF file."
250	echo ""
251	echo -n "	Press enter to try again, or ^C to quit. "
252	read KEYPRESS
253	INFPATH=""
254else
255	echo ""
256	echo "	The file '${INFPATH}' was not found."
257	echo ""
258	echo -n "	Press enter to try again, or ^C to quit. "
259	read KEYPRESS
260	INFPATH=""
261fi
262return
263}
264
265sysconv() {
266header
267echo "			Driver file validation"
268
269if [ ! -r "$SYSPATH" ]; then
270	echo ""
271	echo ""
272	echo "	Now you need to specify the name of the Windows(r) driver .SYS"
273	echo "	file for your device. Note that if you are running FreeBSD/amd64,"
274	echo "	then you must provide a driver that has been compiled for the"
275	echo "	64-bit Windows(r) platform. If a 64-bit driver is not available"
276	echo "	for your device, you must install FreeBSD/i386 and use the"
277	echo "	32-bit driver instead."
278	echo ""
279	echo "	Please type in the path to the Windows(r) driver .SYS file now."
280	echo ""
281	echo -n "	> "
282	read SYSPATH
283fi
284
285if [ ${SYSPATH} ] && [ -e ${SYSPATH} ]; then
286	SYSTYPE=`${FILE} ${SYSPATH}`
287
288	case ${SYSTYPE} in
289	*Windows*)
290		echo ""
291		echo "	This .SYS file appears to be in Windows(r) PE format."
292		echo ""
293		echo -n "	Press return to continue... "
294		read KEYPRESS
295		SYSBASE=`${BASENAME} ${SYSPATH} | ${TR} '.' '_'`
296		;;
297	*)
298		echo ""
299		echo "	I don't recognize this file format. It may not be a valid .SYS file."
300		echo ""
301
302		echo -n "	Press enter to try again, or ^C to quit. "
303		read KEYPRESS
304		SYSPATH=""
305		;;
306	esac
307else
308	echo ""
309	echo "	The file '${SYSPATH}' was not found."
310	echo ""
311	echo -n "	Press enter to try again, or ^C to quit. "
312	read KEYPRESS
313	SYSPATH=""
314fi 
315return
316}
317
318ndiscvt() {
319header
320echo "			Driver file conversion"
321echo ""
322echo "	The script will now try to convert the .INF and .SYS files"
323echo "	using the ndiscvt(1) utility. This utility can handle most"
324echo "	.INF files; however, occasionally it can fail to parse some files"
325echo "	due to subtle syntax issues: the .INF syntax is very complex,"
326echo "	and the Windows(r) parser will sometimes allow files with small"
327echo "	syntax errors to be processed correctly which ndiscvt(1) will"
328echo "	not. If the conversion fails, you may have to edit the .INF"
329echo "	file by hand to remove the offending lines."
330echo ""
331echo -n "	Press enter to try converting the files now: "
332read KEYPRESS
333if ! ${NDISCVT} -i ${INFPATH} -s ${SYSPATH} -O -o ${DNAME}.h > /dev/null; then
334	echo "CONVERSION FAILED"
335	exit
336else
337	echo ""
338	echo "	Conversion was successful."
339	echo ""
340	echo -n "	Press enter to continue... "
341	read KEYPRESS
342fi
343return
344}
345
346firmcvt() {
347	while : ; do
348header
349echo "			Firmware file conversion"
350echo ""
351echo "	If your driver uses additional firmware files, please list them"
352echo "	below. When you're finished, just press enter to continue. (If your"
353echo "	driver doesn't need any extra firmware files, just press enter"
354echo "	to move to the next step.)"
355echo ""
356		echo -n "	> "
357		read FIRMPATH
358
359		if [ ${FIRMPATH} ]; then
360			if [ ! -e ${FIRMPATH} ]; then
361				echo ""
362				echo "	The file '${FIRMPATH}' was not found"
363				echo ""
364				echo -n "	Press enter to try again, or ^C to quit. "
365				read KEYPRESS
366				continue
367			fi
368			if ! ${NDISCVT} -f ${FIRMPATH} > /dev/null; then
369				echo ""
370				echo "CONVERSION FAILED"
371			else
372				echo ""
373				echo "	Conversion was successful."
374				echo ""
375				FRMBASE=`${BASENAME} ${FIRMPATH}`
376				FRMBASE="${FRMBASE}.o"
377				FRMLIST="${FRMLIST} ${FRMBASE}"
378			fi
379			echo -n "	Press enter to continue... "
380			read KEYPRESS
381		else
382			break
383		fi
384	done
385
386header
387echo ""
388echo "	List of files converted firmware files:"
389echo ""
390for i in ${FRMLIST}
391do
392	echo "	"$i
393done
394echo ""
395echo -n "	Press enter to continue... "
396read KEYPRESS
397return
398}
399
400drvgen () {
401header
402echo "			Kernel module generation"
403echo ""
404echo ""
405echo "	The script will now try to generate the kernel driver module."
406echo "	This is the last step. Once this module is generated, you should"
407echo "	be able to load it just like any other FreeBSD driver module."
408echo ""
409echo "	Press enter to compile the stub module and generate the driver"
410echo -n "	module now: "
411read KEYPRESS
412echo ""
413echo -n "	Generating Makefile... "
414echo ".PATH:  ${PWD} ${STUBPATH}"				>  ${MAKEFILE}
415echo "KMOD= ${SYSBASE}"						>> ${MAKEFILE}
416echo "SRCS+= ${STUBFILE} ${DNAME}.h bus_if.h device_if.h"	>> ${MAKEFILE}
417echo "OBJS+=${FRMLIST} ${DNAME}.o"				>> ${MAKEFILE}
418echo "CFLAGS+=	\\"						>> ${MAKEFILE}
419echo "	-DDRV_DATA_START=ndis_${SYSBASE}_drv_data_start \\"		>> ${MAKEFILE}
420echo "	-DDRV_NAME=ndis_${SYSBASE} \\"				>> ${MAKEFILE}
421echo "	-DDRV_DATA_END=ndis_${SYSBASE}_drv_data_end"			>> ${MAKEFILE}
422echo "CLEANFILES+=	\\"					>> ${MAKEFILE}
423echo "	${INFFILE} \\"						>> ${MAKEFILE}
424echo "	${DNAME}.h \\"						>> ${MAKEFILE}
425echo "	${DNAME}.o"						>> ${MAKEFILE}
426echo ".include <bsd.kmod.mk>"					>> ${MAKEFILE}
427if [ -f ${MAKEFILE} ]; then
428	echo "done."
429else
430	echo "generating Makefile failed. Exiting."
431	echo ""
432	exit
433fi
434echo -n "	Building kernel module... "
435echo "" > bus_if.h
436echo "" > device_if.h
437if ! ${MAKE} -f ${MAKEFILE} all > /dev/null; then
438	echo "build failed. Exiting."
439	echo ""
440	exit
441else
442	if [ -f ${SYSBASE}.ko ]; then
443		${MV} ${SYSBASE}.ko ${SYSBASE}.kmod
444		echo "done."
445	else
446		echo "build failed. Exiting."
447		echo ""
448		exit
449	fi
450fi
451echo -n "	Cleaning up... "
452if ! ${MAKE} -f ${MAKEFILE} clean cleandepend > /dev/null; then
453	echo "cleanup failed. Exiting."
454	echo ""
455	exit
456else
457	echo "done."
458fi
459${RM} ${MAKEFILE}
460${MV} ${SYSBASE}.kmod ${SYSBASE}.ko
461echo ""
462echo "	The file ${SYSBASE}.ko has been successfully generated."
463echo "	You can kldload this module to get started."
464echo ""
465echo -n "	Press return to exit. "
466read KEYPRESS
467echo ""
468echo ""
469return
470}
471
472convert_driver () {
473	while : ; do
474		infconv
475		if [ ${INFPATH} ]; then
476			break
477		fi
478	done
479
480	while : ; do
481		sysconv
482		if [ ${SYSPATH} ]; then
483			break
484		fi
485	done
486
487	ndiscvt
488	firmcvt
489	drvgen
490	return
491}
492
493ICONVPATH=/usr/bin/iconv
494NDISCVT=/usr/sbin/ndiscvt
495STUBPATH=/usr/share/misc
496STUBFILE=windrv_stub.c
497DNAME=windrv
498CP=/bin/cp
499MV=/bin/mv
500RM=/bin/rm
501TR=/usr/bin/tr
502FILE=/usr/bin/file
503EGREP=/usr/bin/egrep
504MAKE=/usr/bin/make
505BASENAME=/usr/bin/basename
506TOUCH=/usr/bin/touch
507MKTEMP=/usr/bin/mktemp
508
509MAKEFILE=`${MKTEMP} /tmp/Makefile.XXXXXX`
510INFFILE=`${MKTEMP} /tmp/ascii_inf.XXXXXX`
511
512INFPATH=""
513FRMLIST=""
514SYSPATH=""
515SYSBASE=""
516FRMBASE=""
517
518if [ -r "$1" -a -r "$2" ]; then
519	# Looks like the user supplied .INF and .SYS files on the command line
520	INFPATH=$1
521	SYSPATH=$2
522	convert_driver && exit 0
523fi
524
525while : ; do
526	mainmenu
527	case ${KEYPRESS} in
528	1)
529		help1
530		help2
531		help3
532		help4
533		help5
534		;;
535	2)
536		firmcvt
537		;;
538	3)
539		convert_driver
540		;;
541	4)
542		header
543		echo ""
544		echo "	Be seeing you!"
545		echo ""
546		exit
547		;;
548	*)
549		header
550		echo ""
551		echo -n "	Sorry, I didn't understand that. Press enter to try again: "
552		read KEYPRESS
553		;;
554	esac
555done
556exit
557