Return to BSD News archive
Path: sserve!newshost.anu.edu.au!munnari.oz.au!constellation!convex!convex!convex!darwin.sura.net!howland.reston.ans.net!noc.near.net!ceylon!genesis!steve2 From: steve2@genesis.nred.ma.us Newsgroups: comp.os.386bsd.development Subject: ft dist0.2 part 01/03 Message-ID: <CCtK2x.36z@genesis.nred.ma.us> Date: 4 Sep 93 07:42:32 GMT Organization: Genesis Public Access Unix +1 508 664 0149 Lines: 619 Here is the latest version of my QIC-40/80 tape driver. While it's still not as functional as I would like, I wanted to get this to the masses before my wedding consumes my next few weeks. See the README file enclosed below for details. Enjoy! - Steve Gerakines steve2@genesis.nred.ma.us # This is a shell archive. Save it in a file, remove anything before # this line, and then unpack it by entering "sh file". Note, it may # create directories; files and directories will be owned by you and # have default permissions. # # This archive contains: # # README # driver # driver/fd.c.diff # driver/ftape.h # driver/ftreg.h # echo x - README sed 's/^X//' >README << 'END-of-README' XQIC-40/80 floppy tape driver for 386BSD XSteve Gerakines <steve2@genesis.nred.ma.us> X08/24/93 v0.2 X XHere's the latest and greatest version of my floppy tape driver for X386bsd, along with the basis for a simple QIC-40/80 backup program. XThere have been significant changes between the last release and this Xone. Some highlights are: X X - I/O using read() and write() was abandonded in favor of doing X all I/O using ioctl()'s X X - all I/O is now segment based instead of by sector X X - the segment hunting algorithm has been greatly improved X X - support for different tape lengths and QIC-40 added X X - error correction/badmap support was added X X - streaming I/O seems much more stable X XWhat it can't do yet: X X - formatting/verifying is close but still incomplete X X - error correction is functional but is not robust X XWhat you need before installing: X X - an accurate timer X X - something to reduce interrupt latency X XBoth of these have been provided in the 0.2.3 patchkit and are highly Xrecommended. X X--------------------------------------------------------- X XThe installation comes with three directories: qtar, driver, and Xtools. X XDriver Installtion: X X1. Place the ft.c and ftreg.h files in your /sys/i386/isa directory. X X2. Place the ftape.h file in your /usr/include/sys directory. X X3. Apply the patch file fd.c.diff to your existing fd.c file. This X patch is identical to the one in the v0.1 release of the driver, X so skip this step if it's already applied. For example: X X # cp fd.c.diff /sys/i386/isa X # cd /sys/i386/isa X # patch < fd.c.diff X X If you're not using the stock 0.1 fd driver, you may have to X apply this by hand. In any case sure that the NFD values in X ft.c and fd.c agree. X X4. Modify your /sys/i386/conf/files.i386 file to contain: X X i386/isa/ft.c optional ft device-driver X X5. Modify your config file to have lines like this: X X controller fd0 at isa? port "IO_FD1" bio irq 6 drq 2 vector fdintr X disk fd0 at fd0 drive 0 X disk fd1 at fd0 drive 1 X tape ft0 at fd0 drive 2 X X6. Create the necessary devices. The rmt* devices specified in the 0.1 X release should no longer be used with the floppy tape driver. X X % cd /dev X % mknod ft0a b 2 16 X % mknod rft0a c 9 16 X X Where 2 and 9 are the major numbers for the fd driver. Minor number 16 X is unit number 2 (minor/8 in fd and ft drivers). X X7. Recompile your kernel and reboot. X X % cd /sys/i386/conf X % config CONFIG X % cd /sys/compile/CONFIG X % make clean depend; make X X--------------------------------------------------------- X XTools and qtar: X Xqtar is the basis for a QIC-40/80 backup program. It's command line Xdriven, very similar to tar. Once the driver is installed, you should Xonly have to go to the qtar directory and type "make" to build the Xprogram. X XCurrently the program will only list volumes and give you a table of Xcontents of a tape. Some examples of how it's used: X X qtar t - list the file set directory X qtar tvL -V "foo" - list the file set directory for volume "foo" X qtar -lv - list the volumes on the current tape X XIn the tools directory you'll find a program to read tape segments and Xwrite them to stdout, and another that tests the segment hunting algorithm. X X--------------------------------------------------------- X XPlease report your problems as well as successes to me at Xsteve2@genesis.nred.ma.us. Sending any debugging information along Xwith your problem is extremely helpful. I have a Colorado drive, so XI'm very interested in hearing from other compatible drive owners. X XThe current focus of my work is qtar and the error correction stuff. XI don't expect the driver to have any more radical changes, with the Xexception of some added functionality. The internal workings of Xqtar will definitely undergo some major overhauls, so don't expect Xtoo much of it for now. X XUntil the next release, X- Steve Xsteve2@genesis.nred.ma.us END-of-README echo c - driver mkdir driver > /dev/null 2>&1 echo x - driver/fd.c.diff sed 's/^X//' >driver/fd.c.diff << 'END-of-driver/fd.c.diff' X*** ../fd.c.tape Wed Feb 10 18:46:22 1993 X--- fd.c Sat Jun 5 12:36:22 1993 X*************** X*** 47,67 **** X #include "ioctl.h" X #include "buf.h" X #include "uio.h" X #include "i386/isa/isa_device.h" X #include "i386/isa/fdreg.h" X #include "i386/isa/icu.h" X #include "i386/isa/rtc.h" X #undef NFD X #define NFD 2 X X! #define FDUNIT(s) ((s>>3)&1) X #define FDTYPE(s) ((s)&7) X X #define b_cylin b_resid X #define b_step b_resid X #define FDBLK 512 X #define NUMTYPES 4 X X struct fd_type { X int sectrac; /* sectors per track */ X int secsize; /* size code for sectors */ X--- 47,76 ---- X #include "ioctl.h" X #include "buf.h" X #include "uio.h" X #include "i386/isa/isa_device.h" X #include "i386/isa/fdreg.h" X #include "i386/isa/icu.h" X #include "i386/isa/rtc.h" X #undef NFD X #define NFD 2 X X! #define NFT 1 X! #if NFT > 0 X! extern ftintr(), ftopen(), ftattach(); X! extern int ft_type; X! enum { FT_NONE, FT_MOUNTAIN, FT_COLORADO }; X! extern int fdc_mode; X! enum { FDC_TAPE_MODE, FDC_DISK_MODE }; X! #endif X! X! #define FDUNIT(s) ((s>>3)&3) X #define FDTYPE(s) ((s)&7) X X #define b_cylin b_resid X #define b_step b_resid X #define FDBLK 512 X #define NUMTYPES 4 X X struct fd_type { X int sectrac; /* sectors per track */ X int secsize; /* size code for sectors */ X*************** X*** 184,203 **** X--- 193,220 ---- X } X X fdt <<= 4; X fd_turnoff(i); X hdr = 1; X } X X /* Set transfer to 500kbps */ X outb(fdc+fdctl,0); X fd_turnoff(0); X+ X+ #if NFT > 0 X+ ftattach(fdc); X+ if (ft_type == FT_COLORADO) X+ printf(", %d: Jumbo tape", i); X+ else if (ft_type == FT_MOUNTAIN) X+ printf(", %d: Summit tape", i); X+ #endif X } X X int X fdsize(dev) X dev_t dev; X { X return(0); X } X X /****************************************************************************/ X*************** X*** 315,342 **** X while ((inb(fdc+fdsts) & NE7_RQM) == 0 && i-- > 0); X if (i <= 0) return (-1); X outb(fdc+fddata,x); X return (0); X } X X static fdopenf; X /****************************************************************************/ X /* fdopen/fdclose */ X /****************************************************************************/ X! Fdopen(dev, flags) X! dev_t dev; X! int flags; X { X! int unit = FDUNIT(minor(dev)); X! /*int type = FDTYPE(minor(dev));*/ X int s; X X fdopenf = 1; X /* check bounds */ X if (unit >= NFD) return(ENXIO); X /*if (type >= NUMTYPES) return(ENXIO);*/ X X /* Set proper disk type, only allow one type */ X return 0; X } X X fdclose(dev, flags) X--- 332,360 ---- X while ((inb(fdc+fdsts) & NE7_RQM) == 0 && i-- > 0); X if (i <= 0) return (-1); X outb(fdc+fddata,x); X return (0); X } X X static fdopenf; X /****************************************************************************/ X /* fdopen/fdclose */ X /****************************************************************************/ X! Fdopen(int dev, int flags, int devtype, struct proc *p) X { X! int unit = FDUNIT(minor(dev)); X! /*int type = FDTYPE(minor(dev));*/ X int s; X X+ #if NFT > 0 X+ if (unit == NFD) return(ftopen(dev, flags, devtype, p)); X+ #endif X fdopenf = 1; X /* check bounds */ X if (unit >= NFD) return(ENXIO); X /*if (type >= NUMTYPES) return(ENXIO);*/ X X /* Set proper disk type, only allow one type */ X return 0; X } X X fdclose(dev, flags) X*************** X*** 426,445 **** X--- 444,467 ---- X /****************************************************************************/ X /* fdintr */ X /****************************************************************************/ X fdintr(unit) X { X register struct buf *dp,*bp; X struct buf *dpother; X int read,head,trac,sec,i,s,sectrac,cyl,st0; X unsigned long blknum; X struct fd_type *ft; X+ X+ #if NFT > 0 X+ if (fdc_mode == FDC_TAPE_MODE) return(ftintr(unit)); X+ #endif X X #ifdef FDTEST X printf("state %d, unit %d, dr %d|",fd_state,unit,fd_drive); X #endif X X if (!fdopenf) return; X dp = &fd_unit[fd_drive].head; X bp = dp->b_actf; X read = bp->b_flags & B_READ; X /*ft = &fd_types[FDTYPE(bp->b_dev)];*/ END-of-driver/fd.c.diff echo x - driver/ftape.h sed 's/^X//' >driver/ftape.h << 'END-of-driver/ftape.h' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * ftape.h - floppy tape driver functions X * 08/07/93 v0.2 X * Header file that sits in /sys/sys, first revision. Support for X * ioctl functions added. X */ X X#ifndef _FTAPE_H_ X#define _FTAPE_H_ X X#ifndef _IOCTL_H_ X#include <sys/ioctl.h> X#endif X X/* Miscellaneous constant values */ X#define QCV_BLKSIZE 1024 /* Size of a block */ X#define QCV_SEGSIZE 32768 /* Size of a segment */ X#define QCV_BLKSEG 32 /* Blocks per segment */ X#define QCV_ECCSIZE 3072 /* Bytes ecc eats */ X#define QCV_ECCBLKS 3 /* Blocks ecc eats */ X#define QCV_NFMT 3 /* Number of tape formats */ X#define QCV_NLEN 5 /* Number of tape lengths */ X#define UCHAR unsigned char X#define USHORT unsigned short X#define ULONG unsigned long X X/* Segment request structure. */ Xtypedef struct qic_segment { X ULONG sg_trk; /* Track number */ X ULONG sg_seg; /* Segment number */ X ULONG sg_crcmap; /* Returned bitmap of CRC errors */ X ULONG sg_badmap; /* Map of known bad sectors */ X UCHAR *sg_data; /* Segment w/bad blocks discarded */ X} QIC_Segment; X X/* Tape geometry structure. */ Xtypedef struct tapegeom { X int g_fmtno; /* Format number */ X int g_lenno; /* Length number */ X char g_fmtdesc[16]; /* Format text description */ X char g_lendesc[16]; /* Length text description */ X int g_trktape; /* Number of tracks per tape */ X int g_segtrk; /* Number of segments per track */ X int g_blktrk; /* Number of blocks per track */ X int g_fdtrk; /* Floppy disk tracks */ X int g_fdside; /* Floppy disk sectors/side */ X} QIC_Geom; X X/* Various ioctl() routines. */ X#define QIOREAD _IOWR('q', 1, QIC_Segment) /* Read segment */ X#define QIOWRITE _IOW('q', 2, QIC_Segment) /* Write segment */ X#define QIOREWIND _IO('q', 3) /* Rewind tape */ X#define QIOBOT _IO('q', 4) /* Seek beg of trk */ X#define QIOEOT _IO('q', 5) /* Seek end of trk */ X#define QIOTRACK _IOW('q', 6, int) /* Seek to track */ X#define QIOSEEKLP _IO('q', 7) /* Seek load point */ X#define QIOFORWARD _IO('q', 8) /* Move tape fwd */ X#define QIOSTOP _IO('q', 9) /* Stop tape */ X#define QIOPRIMARY _IO('q', 10) /* Primary mode */ X#define QIOFORMAT _IO('q', 11) /* Format mode */ X#define QIOVERIFY _IO('q', 12) /* Verify mode */ X#define QIOWRREF _IO('q', 13) /* Write ref burst */ X#define QIOSTATUS _IOR('q', 14, int) /* Get drive status */ X#define QIOCONFIG _IOR('q', 15, int) /* Get tape config */ X#define QIOGEOM _IOR('q', 16, QIC_Geom) /* Get geometry */ X X/* QIC drive status bits. */ X#define QS_READY 0x01 /* Drive ready */ X#define QS_ERROR 0x02 /* Error detected */ X#define QS_CART 0x04 /* Tape in drive */ X#define QS_RDONLY 0x08 /* Write protect */ X#define QS_NEWCART 0x10 /* New tape inserted */ X#define QS_FMTOK 0x20 /* Tape is formatted */ X#define QS_BOT 0x40 /* Tape at beginning */ X#define QS_EOT 0x80 /* Tape at end */ X X/* QIC configuration bits. */ X#define QCF_RTMASK 0x18 /* Rate mask */ X#define QCF_RT250 0x00 /* 250K bps */ X#define QCF_RT2 0x01 /* 2M bps */ X#define QCF_RT500 0x02 /* 500K bps */ X#define QCF_RT1 0x03 /* 1M bps */ X#define QCF_EXTRA 0x40 /* Extra length tape */ X#define QCF_QIC80 0x80 /* QIC-80 detected */ X X/* QIC tape status bits. */ X#define QTS_FMMASK 0x0f /* Tape format mask */ X#define QTS_LNMASK 0xf0 /* Tape length mask */ X#define QTS_QIC40 0x01 /* QIC-40 tape */ X#define QTS_QIC80 0x02 /* QIC-80 tape */ X#define QTS_QIC500 0x03 /* QIC-500 tape */ X#define QTS_LEN1 0x10 /* 205 ft/550 Oe */ X#define QTS_LEN2 0x20 /* 307.5 ft/550 Oe */ X#define QTS_LEN3 0x30 /* 295 ft/900 Oe */ X#define QTS_LEN4 0x40 /* 1100 ft/550 Oe */ X#define QTS_LEN5 0x50 /* 1100 ft/900 Oe */ X X/* Tape header segment structure */ Xtypedef struct qic_header { X ULONG qh_sig; /* Header signature 0x55aa55aa */ X UCHAR qh_fmtc; /* Format code */ X UCHAR qh_unused1; X USHORT qh_hseg; /* Header segment number */ X USHORT qh_dhseg; /* Duplicate header segment number */ X USHORT qh_first; /* First logical area data segment */ X USHORT qh_last; /* Last logical area data segment */ X UCHAR qh_fmtdate[4]; /* Most recent format date */ X UCHAR qh_chgdate[4]; /* Most recent tape change date */ X UCHAR qh_unused2[2]; X USHORT qh_tstrk; /* Tape segments per track */ X UCHAR qh_ttcart; /* Tape tracks per cartridge */ X UCHAR qh_mfside; /* Max floppy sides */ X UCHAR qh_mftrk; /* Max floppy tracks */ X UCHAR qh_mfsect; /* Max floppy sector */ X char qh_tname[44]; /* Tape name (ASCII, space filled) */ X UCHAR qh_namdate[4]; /* Date tape was given a name */ X USHORT qh_cprseg; /* Compression map start segment */ X UCHAR qh_unused3[48]; X UCHAR qh_refmt; /* Re-format flag */ X UCHAR qh_unused4; X UCHAR qh_iocount[4]; /* I/O count for life of tape */ X UCHAR qh_unused5[4]; X UCHAR qh_ffmtdate[4]; /* Date first formatted */ X USHORT qh_fmtcount; /* Number of times formatted */ X USHORT qh_badsect; /* Failed sector count */ X char qh_mfname[44]; /* Manufacturer name if pre-formatted */ X char qh_mflot[44]; /* Manufacturer lot code */ X UCHAR qh_unused6[22]; X ULONG qh_fail[448]; /* Failed sector log */ X ULONG qh_badmap[6912]; /* Bad sector map */ X} QIC_Header; X X/* Volume table of contents entry structure. */ Xtypedef struct qic_vtbl { X UCHAR vt_sig[4]; /* Signature "VTBL" if entry used */ X USHORT vt_first; /* Starting segment */ X USHORT vt_last; /* Ending segment */ X char vt_vname[44]; /* Set name */ X UCHAR vt_savdate[4]; /* Date saved */ X UCHAR vt_flags; /* Volume flags */ X UCHAR vt_multi; /* Multi cartidge sequence no. */ X UCHAR vt_vext[26]; /* Extension data */ X char vt_passwd[8]; /* Password for volume */ X UCHAR vt_dirsize[4]; /* Directory section size */ X UCHAR vt_dtasize[4]; /* Data section size */ X USHORT vt_osver; /* Operating System version */ X char vt_label[16]; /* Source drive label */ X UCHAR vt_ldev; /* Logical device origin */ X UCHAR vt_pdev; /* Physical device origin */ X UCHAR vt_cprtype; /* Compression type */ X UCHAR vt_ostype; /* Operating System type */ X UCHAR vt_ostype2; /* Always zero ?? */ X UCHAR vt_isocpr; /* ISO compression type */ X UCHAR vt_unused1[4]; X} QIC_VTbl; X X/* Data compression map structure. */ Xtypedef struct qic_dcmap { X UCHAR dc_sig[4]; /* Siguature "DCMS" */ X USHORT dc_mlen; /* Total map length */ X UCHAR dc_unused1[6]; X ULONG dc_offset[7421]; /* Byte offsets to segments */ X} QIC_DCMap; X X/* System specific file set structures - Unix */ Xtypedef struct qic_unix_set { X UCHAR fsu_perm; /* Permissions */ X UCHAR fsu_attr2; /* More attributes */ X UCHAR fsu_ctime[4]; /* Creation time */ X UCHAR fsu_atime[4]; /* Last access time */ X UCHAR fsu_inode[4]; /* i-node number */ X UCHAR fsu_user[4]; /* User number */ X UCHAR fsu_group[4]; /* Group number */ X UCHAR fsu_major; /* Major device number */ X UCHAR fsu_minor; /* Minor device number */ X UCHAR fsu_nsize; /* Name size */ X UCHAR fsu_name; /* Entry name starts here */ X} QIC_Unix_Set; X X/* File set structure */ Xtypedef struct qic_fileset { X UCHAR fs_size; /* Size of fixed + system size - 1 */ X UCHAR fs_attr; /* Attributes */ X UCHAR fs_mtime; /* Modification time */ X UCHAR fs_dsize[4]; /* Data size */ X} QIC_FileSet; X X#endif /* _FTAPE_H_ */ END-of-driver/ftape.h echo x - driver/ftreg.h sed 's/^X//' >driver/ftreg.h << 'END-of-driver/ftreg.h' X/* X * Copyright (c) 1993 Steve Gerakines X * X * This is freely redistributable software. You may do anything you X * wish with it, so long as the above notice stays intact. X * X * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS X * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED X * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE X * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, X * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES X * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR X * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) X * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, X * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING X * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE X * POSSIBILITY OF SUCH DAMAGE. X * X * ftreg.h - floppy tape driver X * X * 08/07/93 v0.2 release X * Things that should've been here in the first place were moved. X * Tape geometry and segment request types were added. X * X * 06/03/93 v0.1 Alpha release X * Base release. Many more things should be moved here. X */ X X/* QIC-117 command set. */ X#define QC_RESET 1 /* reset */ X#define QC_NEXTBIT 2 /* report next bit */ X#define QC_PAUSE 3 /* pause */ X#define QC_STPAUSE 4 /* step pause */ X#define QC_TIMEOUT 5 /* alt timeout */ X#define QC_STATUS 6 /* report status */ X#define QC_ERRCODE 7 /* report error code */ X#define QC_CONFIG 8 /* report config */ X#define QC_VERSION 9 /* report version */ X#define QC_FORWARD 10 /* logical forward */ X#define QC_SEEKSTART 11 /* seek to track start */ X#define QC_SEEKEND 12 /* seek to track end */ X#define QC_SEEKTRACK 13 /* seek head to track */ X#define QC_SEEKLOAD 14 /* seek load point */ X#define QC_FORMAT 15 /* format mode */ X#define QC_WRITEREF 16 /* write reference */ X#define QC_VERIFY 17 /* verify mode */ X#define QC_STOP 18 /* stop tape */ X#define QC_STEPUP 21 /* step head up */ X#define QC_STEPDOWN 22 /* step head down */ X#define QC_SEEKREV 25 /* seek reverse */ X#define QC_SEEKFWD 26 /* seek forward */ X#define QC_RATE 27 /* select data rate */ X#define QC_DIAG1 28 /* diagnostic mode 1 */ X#define QC_DIAG2 29 /* diagnostic mode 2 */ X#define QC_PRIMARY 30 /* primary mode */ X#define QC_VENDORID 32 /* vendor id */ X#define QC_TSTATUS 33 /* report tape status */ X#define QC_EXTREV 34 /* extended skip reverse */ X#define QC_EXTFWD 35 /* extended skip forward */ X X/* Colorado enable/disable. */ X#define QC_COL_ENABLE1 46 /* enable */ X#define QC_COL_ENABLE2 2 /* null-op */ X#define QC_COL_DISABLE 47 /* disable */ X X/* Mountain enable/disable. */ X#define QC_MTN_ENABLE1 23 /* enable 1 */ X#define QC_MTN_ENABLE2 20 /* enable 2 */ X#define QC_MTN_DISABLE 24 /* disable */ X X/* Segment I/O request. */ Xtypedef struct segq { X unsigned char buff[QCV_SEGSIZE];/* Segment data; first for alignment */ X int reqtype; /* Request type */ X long reqcrc; /* CRC Errors found */ X long reqbad; /* Bad sector map */ X long reqblk; /* Block request starts at */ X int reqcan; /* Cancel read-ahead */ X} SegReq; END-of-driver/ftreg.h exit