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