wdbTsfsDrv.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:38k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* wdbTsfsDrv.c - virtual generic file I/O driver for the WDB agent */
  2. /* Copyright 1996-2001 Wind River Systems, Inc. */
  3. /*
  4. modification history
  5. --------------------
  6. 01s,09oct01,jhw  Fixed memory leak in tsfsOpen(). SPR 67981.
  7. 01r,03mar99,dgp  update to reference project facility, make tsfsOpen() NOMANUAL
  8. 01q,28jan99,jmp  added initialization of semGiveAddr in WDB_TSFS_GENERIC_INFO
  9.                  structure, for TSFS_BOOT facility (SPR# 24466).
  10. 01p,23nov98,cth  added explicit setting of WDB_TSFS_O_TEXT open mode (SPR 23467)
  11. 01o,31aug98,dgp  final editing for WV 2.0 FCS, corrections to tgtsvr stuff
  12. 01n,28aug98,dgp  FCS man page edit, add tgtsvr info
  13. 01m,25aug98,cth  added errno mapping for ECONNREFUSED
  14. 01l,10aug98,cth  FIORENAME now handles prepended device names, updated docs
  15. 01k,27may98,cth  modified docs, removed get snd/rcv buf ioctls
  16. 01j,05may98,dgp  clean up man pages for WV 2.0 beta release
  17. 01i,16apr98,cth  removed debug print statements
  18. 01h,16apr98,cth  mapped errnos from tsfs portable definitions to vxworks'
  19.         added errno reset in open, updated docs
  20. 01g,03apr98,cjtc i960 port for WV20
  21. 01f,19mar98,cth  added ioctl support for sockets
  22. 01e,25feb98,cth  added O_APPEND, _EXCL modes, doc changes, added FIORENAME
  23. 01d,30jan98,cth  added directory creation/deletion, added man page
  24. 01c,18aug97,cth  added FIOSNDURGB ioctl command
  25. 01b,18nov96,dbt  replaced the field delete in WDB_TSFS_INFO struct for C++
  26.                  compatibility, with field remove.
  27. 01a,28aug96,c_s  written, based on wdbVioDrv.c by ms.
  28. */
  29. /*
  30. DESCRIPTION
  31. This library provides a virtual file I/O driver for use with the WDB
  32. agent.  I/O is performed on this virtual I/O device exactly as it would be
  33. on any device referencing a VxWorks file system.  File operations, such as
  34. read() and write(), move data over a virtual I/O channel created between the
  35. WDB agent and the Tornado target server.  The operations are then executed 
  36. on the host file system.  Because file operations are actually performed on 
  37. the host file system by the target server, the file system presented by this 
  38. virtual I/O device is known as the target-server file system, or TSFS.
  39. The driver is installed with wdbTsfsDrv(), creating a device typically
  40. called '/tgtsvr'.  See the manual page for wdbTsfsDrv() for more information
  41. about using this function.  The initialization is done automatically,
  42. enabling access to TSFS, when INCLUDE_WDB_TSFS is defined.
  43. The target server also must have TSFS enabled in order to use TSFS.  See the
  44. .I WindView User's Guide: Data Upload
  45. and the target server documentation.
  46. TSFS SOCKETS
  47. TSFS provides all of the functionality of other VxWorks file systems.
  48. For details, see the 
  49. .pG "I/O System and Local File Systems."
  50. In addition to normal
  51. files, however, TSFS also provides basic access to TCP sockets.  This
  52. includes opening the client side of a TCP socket, reading, writing, and
  53. closing the socket.  Basic setsockopt() commands are also supported.
  54. To open a TCP socket using TSFS, use a filename of the form:
  55. .tS
  56.     TCP:<server_name> | <server_ip>:<port_number>
  57. .tE
  58. To open and connect a TCP socket to a server socket located on a server 
  59. named 'mongoose', listening on port 2010, use the following:
  60. .CS
  61.     fd = open ("/tgtsvr/TCP:mongoose:2010", 0, 0)
  62. .CE
  63. The open flags and permission arguments to the open call are ignored when
  64. opening a socket through TSFS.  If the server 'mongoose' has an IP
  65. number of '144.12.44.12', you can use the following equivalent form of the 
  66. command:
  67. .CS
  68.     fd = open ("/tgtsvr/TCP:144.12.44.12:2010", 0, 0)
  69. .CE
  70. DIRECTORIES
  71. All directory functions, such as mkdir(), rmdir(), opendir(), readdir(),
  72. closedir(), and rewinddir() are supported by TSFS, regardless of
  73. whether the target server providing TSFS is being run on a UNIX or 
  74. Windows host.
  75. While it is possible to open and close directories using open() and close(),
  76. it is not possible to read from a directory using read(). Instead, readdir() 
  77. must be used.  It is also not possible to write to an open directory, and 
  78. opening a directory for anything other than read-only results in an 
  79. error, with 'errno' set to 'EISDIR'.  Calling read() on a directory 
  80. returns 'ERROR' with 'errno' set to 'EISDIR'.
  81. OPEN FLAGS
  82. When the target server that is providing the TSFS is running on a Windows
  83. host, the default file-translation mode is binary translation.  If text
  84. translation is required, then WDB_TSFS_O_TEXT can be included in the mode
  85. argument to open().  For example:
  86. .CS
  87.     fd = open ("/tgtsvr/foo", O_CREAT | O_RDWR | WDB_TSFS_O_TEXT, 0777)
  88. .CE
  89. If the target server providing TSFS services is running on a UNIX host, 
  90. WDB_TSFS_O_TEXT is ignored.
  91. TGTSVR
  92. For general information on the target server, see the reference
  93. entry for 'tgtsvr'. In order to use this library, the target server must
  94. support and be configured with the following options:
  95. .iP "-R <root>" 20
  96. Specify the root of the host's file system that is visible to target processes
  97. using TSFS.  This flag is required to use TSFS.  Files under this root are by
  98. default read only.  To allow read/write access, specify -RW.
  99. .iP "-RW"
  100. Allow read and write access to host files by target processes using
  101. TSFS.  When this option is specified, access to the
  102. target server is restricted as if `-L' were also specified.
  103. IOCTL SUPPORT
  104. TSFS supports the following ioctl() functions for controlling files
  105. and sockets. Details about each function can be found in the documentation 
  106. listed below.
  107. .iP 'FIOSEEK'
  108. .iP 'FIOWHERE'
  109. .iP 'FIOMKDIR'
  110. Create a directory.  The path, in this case '/tgtsvr/tmp', must be an
  111. absolute path prefixed with the device name. To create the directory '/tmp' 
  112. on the root of the TSFS file system use the following:
  113. .CS
  114.     status = ioctl (fd, FIOMKDIR, "/tgtsvr/tmp")
  115. .CE
  116. .iP 'FIORMDIR'
  117. Remove a directory.  The path, in this case '/tgtsvr/foo', must be an 
  118. absolute path prefixed with the device name.  To remove the directory '/foo' 
  119. from the root of the TSFS file system, use the following:
  120. .CS
  121.     status = ioctl (fd, FIORMDIR, "/tgtsvr/foo")
  122. .CE
  123. .iP 'FIORENAME'
  124. Rename the file or directory represented by 'fd' to the name in the string
  125. pointed to by 'arg'.  The path indicated by 'arg' may be prefixed with the
  126. device name or not.  Using this ioctl() function with the path '/foo/goo'
  127. produces the same outcome as the path '/tgtsvr/foo/goo'.  The path is not
  128. modified to account for the current working directory, and therefore must
  129. be an absolute path.
  130. .CS
  131.     char *arg = "/tgtsvr/foo/goo"; 
  132.     status = ioctl (fd, FIORENAME, arg);
  133. .CE
  134. .iP 'FIOREADDIR'
  135. .iP 'FIONREAD'
  136. Return the number of bytes ready to read on a TSFS socket file
  137. descriptor.
  138. .iP 'FIOFSTATGET'
  139. .iP 'FIOGETFL'
  140. .LP
  141. The following ioctl() functions can be used only on socket file
  142. descriptors.  Using these functions with ioctl() provides similar behavior
  143. to the setsockopt() and getsockopt() functions usually used with socket
  144. descriptors.  Each command's name is derived from a
  145. getsockopt()/setsockopt() command and works in exactly the same way as the
  146. respective getsockopt()/setsockopt() command.  The functions setsockopt()
  147. and getsockopt() can not be used with TSFS socket file descriptors.
  148. For example, to enable recording of debugging information on the TSFS socket
  149. file descriptor, call:
  150. .CS
  151.     int arg = 1;
  152.     status = ioctl (fd, SO_SETDEBUG, arg);
  153. .CE
  154. To determine whether recording of debugging information for the TSFS-socket
  155. file descritptor is enabled or disabled, call:
  156. .CS
  157.     int arg;
  158.     status = ioctl (fd, SO_GETDEBUG, & arg);
  159. .CE
  160. After the call to ioctl(), 'arg' contains the state of the debugging attribute.
  161. The ioctl() functions supported for TSFS sockets are:
  162. .iP SO_SETDEBUG
  163. Equivalent to setsockopt() with the SO_DEBUG command.
  164. .iP SO_GETDEBUG
  165. Equivalent to getsockopt() with the SO_DEBUG command.
  166. .iP SO_SETSNDBUF
  167. This command changes the size of the send buffer of the host socket.  The 
  168. configuration of the WDB channel between the host and target also affects the
  169. number of bytes that can be written to the TSFS file descriptor in a single
  170. attempt.
  171. .iP SO_SETRCVBUF
  172. This command changes the size of the receive buffer of the host socket.  The 
  173. configuration of the WDB channel between the host and target also affects the
  174. number of bytes that can be read from the TSFS file descriptor in a single
  175. attempt.
  176. .iP SO_SETDONTROUTE
  177. Equivalent to setsockopt() with the SO_DONTROUTE command.
  178. .iP SO_GETDONTROUTE
  179. Equivalent to getsockopt() with the SO_DONTROUTE command.
  180. .iP SO_SETOOBINLINE
  181. Equivalent to setsockopt() with the SO_OOBINLINE command.
  182. .iP SO_GETOOBINLINE
  183. Equivalent to getsockopt() with the SO_OOBINLINE command.
  184. .iP SO_SNDURGB
  185. The SO_SNDURGB command sends one out-of-band byte (pointed to by 'arg') 
  186. through the socket.
  187. ERROR CODES
  188. The routines in this library return the VxWorks error codes that 
  189. most closely match the errnos generated by the corresponding host function.
  190. If an error is encountered that is due to a WDB failure, a WDB error
  191. is returned instead of the standard VxWorks 'errno'.  If an 'errno' generated
  192. on the host has no reasonable VxWorks counterpart, the host 'errno' is
  193. passed to the target calling routine unchanged.
  194. SEE ALSO:
  195. .I "Tornado User's Guide,"
  196. .I "VxWorks Programmer's Guide: I/O System, Local File Systems"
  197. INTERNAL
  198. opendir(), closedir(), readdir() and rewinddir() are supported when
  199. the tgtsvr is running on a Unix host.  All of these, with the exception of
  200. rewinddir() are supported on Win32.  Win32 provides directory listings with
  201. an iterator model (findfirst(), findnext(), findclose()).  There is no
  202. way to back up this iterator, like rewinddir does.
  203. There are times when the host must return an error code that is not 
  204. defined on the target.  These error codes are defined in wdb.h.  Each
  205. time the errno is set in this function, it is first mapped from the
  206. portable error codes defined in wdb.h to a vxWorks' error code.  Common,
  207. usually Posix, errnos are passed through this mapping unchanged.  If
  208. an errno generated on the host is not understood by the mapping routines,
  209. then it is passed through unchanged.  This may give the user useful 
  210. information about what has happened when vxWorks doesn't have an 
  211. equivalent errno.  Many of the errnos mapped are the Win32 socket and
  212. networking errnos, which have vxWorks counterparts, but are very different
  213. from unix and vxWorks definitions.
  214. The ioctl command FIORENAME does not work ideally.  It should modify the path
  215. it is handed to account for the current working directory.  Doing this however
  216. requires that this wdb-virtual-io driver call into ioLib, something that has
  217. been avoided so far.  This creates a problem with rename() that is not seen
  218. in dosFsLib.  The rename function, in ioLib, does not patch up the path name
  219. with the current working directory, letting the ioctl in dosFsLib do it
  220. instead.  When the current working directory is '/tgtsvr/foo/goo', and it 
  221. contains the file 'file1', and the tsfsRoot is '/folk/blimpy', calling 
  222. 'rename ("file1", "file-renamed") results in /folk/blimpy/foo/goo/file1
  223. being renamed to /folk/blimpy/file-renamed.  Notice the /foo/goo working
  224. directory was ignored.  By the way, passFsLib has the same problem.
  225. */
  226. #include "vxWorks.h"
  227. #include "ioLib.h"
  228. #include "iosLib.h"
  229. #include "tyLib.h"
  230. #include "stdlib.h"
  231. #include "stdio.h"
  232. #include "intLib.h"
  233. #include "string.h"
  234. #include "sys/stat.h"
  235. #include "dirent.h"
  236. #include "wdb/wdb.h"
  237. #include "wdb/wdbLibP.h"
  238. #include "wdb/wdbEvtLib.h"
  239. #include "wdb/wdbVioLib.h"
  240. #include "wdb/wdbLibP.h"
  241. #if (defined (CPU_FAMILY) && (CPU_FAMILY==I960) && (defined __GNUC__))
  242. #pragma align 1                 /* tell gcc960 not to optimize alignments */
  243. #endif  /* CPU_FAMILY==I960 */
  244. typedef struct
  245.     {
  246.     DEV_HDR devHdr; /* device header */
  247.     } TSFS_DEV;
  248. typedef struct
  249.     {
  250.     int channel; /* tsfs channel number */
  251.     int openmode; /* used for FIOGETFL */
  252.     SEMAPHORE tsfsSem; /* mutex sem for access */
  253.     SEMAPHORE waitSem; /* used to wait for tgtsvr */
  254.     WDB_EVT_NODE evtNode; /* agent event node */
  255.     WDB_TSFS_INFO info; /* event contents */
  256.     struct
  257. {
  258. TGT_INT_T value; /* value to return to caller */
  259. TGT_INT_T errNo; /* errno to return to caller */
  260. TGT_INT_T extra1; /* for ioctl extra results */
  261. TGT_INT_T extra2; /* for ioctl extra results */
  262. } result;
  263.     } TSFS_CHANNEL_DESC;
  264. #if (defined (CPU_FAMILY) && (CPU_FAMILY==I960) && (defined __GNUC__))
  265. #pragma align 0                 /* turn off alignment requirement */
  266. #endif  /* CPU_FAMILY==I960 */
  267. static int tsfsDrvNum; /* drvnum for this driver */
  268. static int tsfsChanNum; /* next channel number */
  269. static TSFS_DEV tsfsDev; /* virtual I/O device */
  270. /* globals */
  271. int mutexOptionsTsfsDrv   = SEM_Q_PRIORITY | SEM_DELETE_SAFE;
  272. int binaryOptionsTsfsDrv  = SEM_Q_FIFO;
  273. int wdbTsfsDefaultDirPerm = DEFAULT_DIR_PERM; /* created directory perms */
  274. /* forward declarations */
  275. static int  tsfsCreate   (TSFS_DEV *pDev, char *name, int mode);
  276. static int      tsfsOpen     (TSFS_DEV *pDev, char * name, int mode, 
  277.       int perm);
  278. static int      tsfsDelete   (TSFS_DEV *pDev, char * name);
  279. static STATUS   tsfsClose    (TSFS_CHANNEL_DESC *pChannelDesc);
  280. static int  tsfsRead     (TSFS_CHANNEL_DESC *pNetFd, char *buf,
  281.       int maxBytes);
  282. static int  tsfsWrite    (TSFS_CHANNEL_DESC *pNetFd, char *buf,
  283.       int maxBytes);
  284. static STATUS tsfsIoctl    (TSFS_CHANNEL_DESC *pChannelDesc,
  285.       int request, int arg);
  286. static int tsfsErrnoMap (int hostErrno);
  287. static void tsfsEventGet (void * pChannelDesc,
  288.       WDB_EVT_DATA *pEvtData);
  289. static void tsfsEventDeq (void * pChannelDesc);
  290. /*******************************************************************************
  291. *
  292. * wdbTsfsDrv - initialize the TSFS device driver for a WDB agent
  293. *
  294. * This routine initializes the VxWorks virtual I/O "2" driver and creates
  295. * a TSFS device of the specified name.
  296. *
  297. * This routine should be called exactly once, before any reads, writes, or
  298. * opens.  Normally, it is called by usrRoot() in usrConfig.c,
  299. * and the device name created is '/tgtsvr'.
  300. *
  301. * After this routine has been called, individual virtual I/O channels
  302. * can be opened by appending the host file name to the virtual I/O
  303. * device name.  For example, to get a file descriptor for the host
  304. * file '/etc/passwd', call open() as follows:
  305. * .CS
  306. *     fd = open ("/tgtsvr/etc/passwd", O_RDWR, 0)
  307. * .CE
  308. *
  309. * RETURNS: OK, or ERROR if the driver can not be installed.
  310. */
  311. STATUS wdbTsfsDrv
  312.     (
  313.     char * name /* root name in i/o system */
  314.     )
  315.     {
  316.     /* check if driver already installed */
  317.     if (tsfsDrvNum > 0)
  318. return (OK);
  319.     tsfsDrvNum = iosDrvInstall (tsfsCreate, tsfsDelete, tsfsOpen,
  320. tsfsClose, tsfsRead, tsfsWrite, 
  321. tsfsIoctl);
  322.     if (tsfsDrvNum <= 0)
  323.         return (ERROR);
  324.     /* Add the device to the I/O systems device list */
  325.     return (iosDevAdd (&tsfsDev.devHdr, name, tsfsDrvNum));
  326.     }
  327. /*******************************************************************************
  328. *
  329. * tsfsCreate - open a virtual I/O channel
  330. *
  331. * RETURNS: tsfsDev handle
  332. */
  333. static int tsfsCreate
  334.     (
  335.     TSFS_DEV * pDev, /* I/O system device entry */
  336.     char * name, /* name of file to open */
  337.     int mode /* VxWorks open mode */
  338.     )
  339.     {
  340.     return tsfsOpen (pDev, name, mode | O_CREAT | O_TRUNC, 0666);
  341.     }
  342. /*******************************************************************************
  343. *
  344. * tsfsOpen - open a virtual I/O channel
  345. *
  346. * This routine opens a virtual I/O channel and returns a device handle
  347. * for the channel.  It does this by creating a WDB event containing the
  348. * information necessary for the tgtsvr to perform the requested open
  349. * operation.  This routine waits, after the event is sent to the tgtsvr,
  350. * until the tgtsvr stores the results of the request back to target memory.
  351. * These results are handed back to the caller.
  352. *
  353. * This routine is also used to create files and directories.  After the file
  354. * or directory is created, it is opened and a valid device handle is handed
  355. * back to the caller.
  356. *
  357. * Note, when creating a directory, the mode argument (O_RDWR, O_RDONLY...)
  358. * is not necessary, except to indicate O_CREAT.  It is illegal in most file
  359. * systems, including all of VxWorks' file systems, to open a directory in
  360. * any mode other than O_RDONLY.  Because the directory is created, as well
  361. * as opened in this routine, it is unreasonable to expect that the mode be
  362. * O_RDONLY in order to succeed.  After all, the user wants to create the
  363. * directory, not open it.  This is confused by our implementation of mkdir,
  364. * where open is used to do the creation.  To resolve the problem here, the
  365. * mode is coerced to O_RDONLY when a directory is being created.  Opening a
  366. * directory (not creating it too) will rightfully fail if the mode is
  367. * anything other than O_RDONLY.
  368. *
  369. * NOMANUAL
  370. *
  371. * RETURNS: tsfsDev handle
  372. */
  373. static int tsfsOpen
  374.     (
  375.     TSFS_DEV * pDev, /* I/O system device entry */
  376.     char * name, /* name of file to open */
  377.     int mode, /* VxWorks open mode */
  378.     int perm /* permission bits */
  379.     )
  380.     {
  381.     TSFS_CHANNEL_DESC * pChannel; /* channel handle */
  382.     int pmode = 0; /* portable open mode */
  383.     int pperm; /* portable open permission-word */
  384.     /* create a channel descriptor */
  385.     pChannel = (TSFS_CHANNEL_DESC *) malloc (sizeof (TSFS_CHANNEL_DESC));
  386.     if (pChannel == NULL)
  387. {
  388. errno = tsfsErrnoMap (ENOMEM);
  389. return ERROR;
  390. }
  391.     /* initialize the channel descriptor */
  392.     pChannel->channel = tsfsChanNum++;
  393.     semMInit (&pChannel->tsfsSem, mutexOptionsTsfsDrv);
  394.     semBInit (&pChannel->waitSem, binaryOptionsTsfsDrv, SEM_EMPTY);
  395.     /* initialize our event node */
  396.     wdbEventNodeInit (&pChannel->evtNode, tsfsEventGet, tsfsEventDeq,
  397.       pChannel);
  398.     /* Now format up an event. */
  399.     pChannel->info.info.channel = pChannel->channel;
  400.     pChannel->info.info.opcode = WDB_TSFS_OPEN;
  401.     pChannel->info.info.semId = (TGT_ADDR_T) &pChannel->waitSem;
  402.     pChannel->info.info.pResult = (TGT_ADDR_T) &pChannel->result.value;
  403.     pChannel->info.info.pErrno = (TGT_ADDR_T) &pChannel->result.errNo;
  404.     pChannel->info.info.semGiveAddr = (TGT_ADDR_T) &semGive;
  405.     pChannel->info.extra.open.filename = (TGT_ADDR_T) name;
  406.     pChannel->info.extra.open.fnameLen = strlen (name);
  407.     pChannel->openmode = mode;
  408.     /* Map between VxWorks modes and portable TSFS modes. */
  409.     if (mode & O_CREAT)
  410. {
  411. pmode |= WDB_TSFS_O_CREAT;
  412. mode &= ~O_CREAT;
  413. }
  414.     if (mode & O_TRUNC)
  415. {
  416. pmode |= WDB_TSFS_O_TRUNC;
  417. mode &= ~O_TRUNC;
  418. }
  419.     if (mode & O_APPEND)
  420. {
  421. pmode |= WDB_TSFS_O_APPEND;
  422. mode &= ~O_APPEND;
  423. }
  424.     if (mode & O_EXCL)
  425. {
  426. pmode |= WDB_TSFS_O_EXCL;
  427. mode &= ~O_EXCL;
  428. }
  429.     if (mode & WDB_TSFS_O_TEXT)
  430. {
  431. pmode |= WDB_TSFS_O_TEXT;
  432. mode &= ~WDB_TSFS_O_TEXT;
  433. }
  434.     switch (mode)
  435. {
  436. case O_RDONLY: pmode |= WDB_TSFS_O_RDONLY; break;
  437. case O_RDWR: pmode |= WDB_TSFS_O_RDWR;   break;
  438. case O_WRONLY: pmode |= WDB_TSFS_O_WRONLY; break;
  439. }
  440.     pChannel->info.extra.open.mode = pmode;
  441.     /* 
  442.      * If we are creating a file, regular or directory, we let the host side
  443.      * know what type by using the permission word.  Here we map between
  444.      * VxWorks' FSTAT_DIR/REG and the portable TSFS file types.  See the
  445.      * comments above about coercing the mode to O_RDONLY when creating
  446.      * a directory.  This coersion is done in the tgtsvr rather than here.
  447.      */
  448.     pperm = perm;
  449.     if (pmode & WDB_TSFS_O_CREAT)
  450. {
  451. if (perm & FSTAT_DIR)
  452.     {
  453.     pperm |= WDB_TSFS_S_IFDIR;
  454.     pperm &= ~FSTAT_DIR;
  455.     }
  456.         else
  457.     {
  458.     pperm |= WDB_TSFS_S_IFREG;
  459.     pperm &= ~FSTAT_REG;
  460.             }
  461.         }
  462.     pChannel->info.extra.open.perm = pperm;
  463.     /* Post the event. */
  464.     wdbEventPost (&pChannel->evtNode);
  465.     /* Wait for the tgtsvr to get back to us with the result. */
  466.     semTake (&pChannel->waitSem, WAIT_FOREVER);
  467.     if (pChannel->result.errNo == OK)
  468. {
  469.         errno = 0;
  470. return (int) pChannel;
  471. }
  472.     errno = tsfsErrnoMap (pChannel->result.errNo);
  473.     free (pChannel);
  474.     return ERROR;
  475.     }
  476. /*******************************************************************************
  477. *
  478. * tsfsDelete - delete a file via the target server
  479. *
  480. * RETURNS: status
  481. * NOMANUAL
  482. */
  483. static int tsfsDelete
  484.     (
  485.     TSFS_DEV * pDev, /* I/O system device entry */
  486.     char * name /* name of file to destroy */
  487.     )
  488.     {
  489.     int result;
  490.     TSFS_CHANNEL_DESC * pChannel; /* channel handle */
  491.     /* 
  492.      * for delete, we aren't given a channel to begin with.  We'll have
  493.      * to create one just for this operation. 
  494.      */
  495.     pChannel = (TSFS_CHANNEL_DESC *) malloc (sizeof (TSFS_CHANNEL_DESC));
  496.     if (pChannel == NULL)
  497. {
  498. errno = tsfsErrnoMap (ENOMEM);
  499. return ERROR;
  500. }
  501.     /*
  502.      * For non-file requests (i.e., ones like delete, where we don't 
  503.      * have an open file handle before we attempt the request), we 
  504.      * set the channel number to -1.
  505.      */
  506.     pChannel->channel = -1;
  507.     semBInit (&pChannel->waitSem, binaryOptionsTsfsDrv, SEM_EMPTY);
  508.     /* initialize our event node */
  509.     wdbEventNodeInit (&pChannel->evtNode, tsfsEventGet, tsfsEventDeq,
  510.       pChannel);
  511.     /* Now format up an event. */
  512.     pChannel->info.info.channel = pChannel->channel;
  513.     pChannel->info.info.opcode = WDB_TSFS_DELETE;
  514.     pChannel->info.info.semId = (TGT_ADDR_T) &pChannel->waitSem;
  515.     pChannel->info.info.pResult = (TGT_ADDR_T) &pChannel->result.value;
  516.     pChannel->info.info.pErrno = (TGT_ADDR_T) &pChannel->result.errNo;
  517.     pChannel->info.info.semGiveAddr = (TGT_ADDR_T) &semGive;
  518.     pChannel->info.extra.remove.filename = (TGT_ADDR_T) name;
  519.     pChannel->info.extra.remove.fnameLen = strlen (name);
  520.     /* Post the event. */
  521.     wdbEventPost (&pChannel->evtNode);
  522.     /* Wait for the tgtsvr to get back to us with the result. */
  523.     semTake (&pChannel->waitSem, WAIT_FOREVER);
  524.     result = pChannel->result.value;
  525.     errno = tsfsErrnoMap (pChannel->result.errNo);
  526.     /* discard the temporary channel */
  527.     semTerminate (&pChannel->waitSem);
  528.     free (pChannel);
  529.     return result;
  530.     }
  531. /******************************************************************************
  532. *
  533. * tsfsClose - close a TSFS file
  534. *
  535. * RETURNS: status
  536. * NOMANUAL
  537. */ 
  538. static STATUS tsfsClose
  539.     (
  540.     TSFS_CHANNEL_DESC * pChannel /* channel handle */
  541.     )
  542.     {
  543.     int result;
  544.     semTake (&pChannel->tsfsSem, WAIT_FOREVER);
  545.     /* prepare the event for transmission */
  546.     pChannel->info.info.channel = pChannel->channel;
  547.     pChannel->info.info.opcode = WDB_TSFS_CLOSE;
  548.     pChannel->info.info.semId = (TGT_ADDR_T) &pChannel->waitSem;
  549.     pChannel->info.info.pResult = (TGT_ADDR_T) &pChannel->result.value;
  550.     pChannel->info.info.pErrno = (TGT_ADDR_T) &pChannel->result.errNo;
  551.     pChannel->info.info.semGiveAddr = (TGT_ADDR_T) &semGive;
  552.     /* Post the event. */
  553.     wdbEventPost (&pChannel->evtNode);
  554.     /* Wait for the tgtsvr to get back to us with the result. */
  555.     semTake (&pChannel->waitSem, WAIT_FOREVER);
  556.     if (pChannel->result.errNo != OK)
  557. errno = tsfsErrnoMap (pChannel->result.errNo);
  558.     /* XXX - reexamine this for reentrancy issues */
  559.     result = pChannel->result.value;
  560.     semGive (&pChannel->tsfsSem);
  561.     semTerminate (&pChannel->tsfsSem);
  562.     semTerminate (&pChannel->waitSem);
  563.     
  564.     free (pChannel);
  565.     return result;
  566.     }
  567. /*******************************************************************************
  568. *
  569. * tsfsRead - read from a TSFS file
  570. *
  571. * RETURNS: the number of bytes read if successful, or ERROR with errno set 
  572. *          to indicate the error.
  573. * NOMANUAL
  574. */
  575. static int tsfsRead
  576.     (
  577.     TSFS_CHANNEL_DESC * pChannel, /* channel handle */
  578.     char * buf, /* buffer to receive data */
  579.     int maxBytes /* max bytes to transfer */
  580.     )
  581.     {
  582.     int result;
  583.     semTake (&pChannel->tsfsSem, WAIT_FOREVER);
  584.     /* prepare the event for transmission */
  585.     pChannel->info.info.channel = pChannel->channel;
  586.     pChannel->info.info.opcode = WDB_TSFS_READ;
  587.     pChannel->info.info.semId = (TGT_ADDR_T) &pChannel->waitSem;
  588.     pChannel->info.info.pResult = (TGT_ADDR_T) &pChannel->result.value;
  589.     pChannel->info.info.pErrno = (TGT_ADDR_T) &pChannel->result.errNo;
  590.     pChannel->info.info.semGiveAddr = (TGT_ADDR_T) &semGive;
  591.     pChannel->info.extra.rw.buffer = (TGT_ADDR_T) buf;
  592.     pChannel->info.extra.rw.nBytes = maxBytes;
  593.     /* Post the event. */
  594.     wdbEventPost (&pChannel->evtNode);
  595.     /* Wait for the tgtsvr to get back to us with the result. */
  596.     semTake (&pChannel->waitSem, WAIT_FOREVER);
  597.     if (pChannel->result.errNo != OK)
  598. errno = tsfsErrnoMap (pChannel->result.errNo);
  599.     result = pChannel->result.value;
  600.     semGive (&pChannel->tsfsSem);
  601.     return result;
  602.     }
  603. /*******************************************************************************
  604. * tsfsWrite - write to a TSFS file
  605. *
  606. * RETURNS:  the number of bytes written if successful, or ERROR with errno 
  607. *           set to indicate the error.
  608. * NOMANUAL
  609. */
  610. static int tsfsWrite
  611.     (
  612.     TSFS_CHANNEL_DESC * pChannel, /* channel handle */
  613.     char * buf, /* buffer of data to be sent */
  614.     int maxBytes /* max bytes to transfer */
  615.     )
  616.     {
  617.     int result;
  618.     semTake (&pChannel->tsfsSem, WAIT_FOREVER);
  619.     /* prepare the event for transmission */
  620.     pChannel->info.info.channel = pChannel->channel;
  621.     pChannel->info.info.opcode = WDB_TSFS_WRITE;
  622.     pChannel->info.info.semId = (TGT_ADDR_T) &pChannel->waitSem;
  623.     pChannel->info.info.pResult = (TGT_ADDR_T) &pChannel->result.value;
  624.     pChannel->info.info.pErrno = (TGT_ADDR_T) &pChannel->result.errNo;
  625.     pChannel->info.info.semGiveAddr = (TGT_ADDR_T) &semGive;
  626.     pChannel->info.extra.rw.buffer = (TGT_ADDR_T) buf;
  627.     pChannel->info.extra.rw.nBytes = maxBytes;
  628.     /* Post the event. */
  629.     wdbEventPost (&pChannel->evtNode);
  630.     /* Wait for the tgtsvr to get back to us with the result. */
  631.     semTake (&pChannel->waitSem, WAIT_FOREVER);
  632.     if (pChannel->result.errNo != OK)
  633. errno = tsfsErrnoMap (pChannel->result.errNo);
  634.     result = pChannel->result.value;
  635.     semGive (&pChannel->tsfsSem);
  636.     return result;
  637.     }
  638. /*******************************************************************************
  639. * tsfsIoctl - special device control
  640. *
  641. * RETURNS: status
  642. * NOMANUAL
  643. */
  644. static STATUS tsfsIoctl
  645.     (
  646.     TSFS_CHANNEL_DESC * pChannel, /* device to control */
  647.     int  request, /* request code */
  648.     int  arg /* some argument */
  649.     )
  650.     {
  651.     int result;
  652.     DIR * pDir = (DIR *) arg; /* For FIOREADDIR Only */
  653.     int pNewChannel; /* for FIOMKDIR */
  654.     char * pShortPath; /* for same */
  655.     semTake (&pChannel->tsfsSem, WAIT_FOREVER);
  656.     /* map between VxWorks ioctl codes and supported TSFS codes */
  657.     switch (request)
  658. {
  659. case FIOSEEK:
  660.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_FIOSEEK;
  661.     break;
  662.         case FIOWHERE:
  663.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_FIOWHERE;
  664.     break;
  665. case FIONREAD:
  666.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_FIONREAD;
  667.     break;
  668.     
  669. case FIOFSTATGET:
  670.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_FIOFSTATGET;
  671.     break;
  672.         case SO_SNDURGB:
  673.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_SNDURGB;
  674.     break;
  675.         case SO_SETDEBUG:
  676.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_SETDEBUG;
  677.     break;
  678.         case SO_GETDEBUG:
  679.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_GETDEBUG;
  680.     break;
  681.         case SO_SETSNDBUF:
  682.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_SETSNDBUF;
  683.     break;
  684.         case SO_SETRCVBUF:
  685.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_SETRCVBUF;
  686.     break;
  687.         case SO_SETDONTROUTE:
  688.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_SETDONTROUTE;
  689.     break;
  690.         case SO_GETDONTROUTE:
  691.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_GETDONTROUTE;
  692.     break;
  693.         case SO_SETOOBINLINE:
  694.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_SETOOBINLINE;
  695.     break;
  696.         case SO_GETOOBINLINE:
  697.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_SO_GETOOBINLINE;
  698.     break;
  699. case FIOREADDIR:
  700.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_FIOREADDIR;
  701.     /* 
  702.      * For FIOREADDIR we want to provide the address of the 
  703.      * struct dirent * and the dd_cookie. 
  704.        */
  705.     
  706.     pChannel->result.extra1 = pDir->dd_cookie;
  707.     pChannel->result.extra2 = (TGT_INT_T) &pDir->dd_dirent;
  708.     break;
  709.         case FIORENAME:
  710.     pChannel->info.extra.ioctl.request = WDB_TSFS_IOCTL_FIORENAME;
  711.     /* 
  712.      * If the new name starts with the device name, strip the
  713.      * device name first.  If it doesn't just continue.
  714.      */
  715.             if ((pShortPath = strstr ((char *) arg, 
  716.       tsfsDev.devHdr.name)) != NULL)
  717. {
  718. /* 
  719.  * If the device name is in the path, but not the first 
  720.  * element of the path, use the whole path.  Otherwise
  721.  * remove the device name.  For example, /tgtsvr/foo/goo
  722.  * should yield /foo/goo, but /foo/tgtsvr/goo should 
  723.  * remain /foo/tgtsvr/goo (/tgtsvr is the dev name).
  724.  */
  725.                 if (pShortPath != (char *) arg)
  726.     pShortPath = (char *) arg;
  727.                 else
  728.                     pShortPath = (char *) arg + strlen (tsfsDev.devHdr.name);
  729. }
  730.             else
  731. {
  732.                 pShortPath = (char *) arg;
  733. }
  734.     /* 
  735.      * We put the length of the new name in extra1, and the address
  736.      * of the new name in extra2.
  737.      */
  738.     pChannel->result.extra1 = strlen (pShortPath);
  739.     pChannel->result.extra2 = (TGT_INT_T) pShortPath;
  740.     break;
  741. case FIOMKDIR:
  742.     /*
  743.      * We handle this by using our own tsfsOpen to do the creation.
  744.      * The device name must prefix the path or we generate an error.
  745.      * Start by stripping off the device name.
  746.      */
  747.              
  748.             if ((pShortPath = strstr ((char *) arg, 
  749.       tsfsDev.devHdr.name)) == NULL)
  750. {
  751.         errno = tsfsErrnoMap (WDB_ERR_INVALID_PARAMS);
  752.         semGive (&pChannel->tsfsSem);
  753. return (ERROR);
  754. }
  755.             /* The device must be the first thing in the path. */
  756.             if (pShortPath != (char *) arg)
  757. {
  758.         errno = tsfsErrnoMap (WDB_ERR_INVALID_PARAMS);
  759.         semGive (&pChannel->tsfsSem);
  760. return (ERROR);
  761. }
  762.             pShortPath = (char *) arg + strlen (tsfsDev.devHdr.name);
  763.             /* 
  764.      * Now we have the proper path, use our own tsfsOpen to create 
  765.      * the directory.  The tsfsDev arg to tsfsOpen isn't used by 
  766.      * tsfsOpen.
  767.              */
  768.     if ((pNewChannel = 
  769.  tsfsOpen (& tsfsDev, pShortPath, O_CREAT | O_RDONLY, 
  770.    FSTAT_DIR | wdbTsfsDefaultDirPerm)) == ERROR)
  771.                 {
  772.         semGive (&pChannel->tsfsSem);
  773.         return ERROR;
  774. }
  775.             /* Close the new channel and return. */
  776.     if (tsfsClose ((TSFS_CHANNEL_DESC *) pNewChannel) != OK)
  777. {
  778.         semGive (&pChannel->tsfsSem);
  779.         return ERROR;
  780. }
  781.             semGive (&pChannel->tsfsSem);
  782.     return (OK);
  783. case FIORMDIR:
  784.     {
  785.     struct stat  statBuf;
  786.     statBuf.st_mode = 0;
  787.     /*
  788.      * We handle this using our own tsfsDelete to remove the 
  789.      * directory.  The device name must prefix the path or we 
  790.      * generate an error.  Start by stripping off the device name.
  791.      */
  792.              
  793.             if ((pShortPath = strstr ((char *) arg, 
  794.       tsfsDev.devHdr.name)) == NULL)
  795. {
  796.         errno = tsfsErrnoMap (WDB_ERR_INVALID_PARAMS);
  797.         semGive (&pChannel->tsfsSem);
  798. return (ERROR);
  799. }
  800.             /* The device must be the first thing in the path. */
  801.             if (pShortPath != (char *) arg)
  802. {
  803.         errno = tsfsErrnoMap (WDB_ERR_INVALID_PARAMS);
  804.         semGive (&pChannel->tsfsSem);
  805. return (ERROR);
  806. }
  807.             pShortPath = (char *) arg + strlen (tsfsDev.devHdr.name);
  808.             /* 
  809.      * Now we have the proper path, but we have to ensure the file
  810.      * is a directory before we can remove it.  Use our own tsfsIoctl
  811.      * with FIOSTATGET to find out if it is.  We open the path, test
  812.      * if it points to a directory, then close it.  Then we delete it.
  813.      */
  814.     pNewChannel = tsfsOpen (& tsfsDev, pShortPath, O_RDONLY, 
  815.             wdbTsfsDefaultDirPerm);
  816.             tsfsIoctl ((TSFS_CHANNEL_DESC *) pNewChannel, FIOFSTATGET, 
  817.        (int) &statBuf);
  818.     tsfsClose ((TSFS_CHANNEL_DESC *) pNewChannel);
  819.             if (! (statBuf.st_mode & S_IFDIR))
  820. {
  821. errno = tsfsErrnoMap (ENOTDIR);
  822.         semGive (&pChannel->tsfsSem);
  823. return (ERROR);
  824. }
  825.      
  826.     /* 
  827.      * We are sure the file is a directory, so we use tsfsDelete to
  828.      * remove the directory.  The tsfsDev arg to tsfsDelete isn't 
  829.      * used by tsfsDelete.  Try to return the most useful errno
  830.      * by making sure errno records only the errors in tsfsDelete.
  831.              */
  832.            
  833.     errno = 0;
  834.             if (tsfsDelete (& tsfsDev, pShortPath) != OK)
  835. {
  836.         semGive (&pChannel->tsfsSem);
  837. return (ERROR);
  838. }
  839.     semGive (&pChannel->tsfsSem);
  840.     return (OK);
  841.             }
  842. case FIOGETFL:
  843.     /* this one is handled locally. */
  844.     *((int *) arg) = pChannel->openmode;
  845.     semGive (&pChannel->tsfsSem);
  846.     return (OK);
  847.     
  848. /* don't pass unknown ioctl's up to target server. */
  849. default:
  850.     errno = tsfsErrnoMap (WDB_ERR_INVALID_PARAMS);
  851.     semGive (&pChannel->tsfsSem);
  852.     return ERROR;
  853. }
  854.     /* prepare the event for transmission */
  855.     pChannel->info.info.channel = pChannel->channel;
  856.     pChannel->info.info.opcode = WDB_TSFS_IOCTL;
  857.     pChannel->info.info.semId = (TGT_ADDR_T) &pChannel->waitSem;
  858.     pChannel->info.info.pResult = (TGT_ADDR_T) &pChannel->result.value;
  859.     pChannel->info.info.pErrno = (TGT_ADDR_T) &pChannel->result.errNo;
  860.     pChannel->info.info.semGiveAddr = (TGT_ADDR_T) &semGive;
  861.     pChannel->info.extra.ioctl.arg = arg;
  862.     pChannel->info.extra.ioctl.pExtra1 = (TGT_ADDR_T) &pChannel->result.extra1;
  863.     pChannel->info.extra.ioctl.pExtra2 = (TGT_ADDR_T) &pChannel->result.extra2;
  864.     /* Post the event. */
  865.     wdbEventPost (&pChannel->evtNode);
  866.     /* Wait for the tgtsvr to get back to us with the result. */
  867.     semTake (&pChannel->waitSem, WAIT_FOREVER);
  868.     if (pChannel->result.errNo != OK)
  869. errno = tsfsErrnoMap (pChannel->result.errNo);
  870.     /* 
  871.      * Some ioctl() requests require us to fill in data pointed to by arg.
  872.      * If so we take care of that here.
  873.      */
  874.     switch (request)
  875. {
  876. case FIOFSTATGET:
  877.     {
  878.     struct stat * pStat = (struct stat *) arg;
  879.     memset (pStat, 0, sizeof (struct stat));
  880.     pStat->st_dev = (int) &tsfsDev;
  881.     pStat->st_size = pChannel->result.extra1;
  882.     if (pChannel->result.extra2 & WDB_TSFS_S_IFREG)
  883. pStat->st_mode |= S_IFREG;
  884.     if (pChannel->result.extra2 & WDB_TSFS_S_IFDIR)
  885. pStat->st_mode |= S_IFDIR;
  886.     break;
  887.     }
  888. case FIONREAD:
  889.     {
  890.     * ((int *) arg) = pChannel->result.extra1;
  891.     break;
  892.     }
  893. case FIOREADDIR:
  894.     {
  895.     pDir->dd_cookie = pChannel->result.extra1;
  896.     break;
  897.     }
  898. case SO_GETDEBUG:
  899. case SO_GETDONTROUTE:
  900. case SO_GETOOBINLINE:
  901.     {
  902.     * ((int *) arg) = pChannel->result.extra1;
  903.     break;
  904.     }
  905. }
  906.     result = pChannel->result.value;
  907.     semGive (&pChannel->tsfsSem);
  908.     return result;
  909.     }
  910. /******************************************************************************
  911. *
  912. * tsfsErrnoMap - map errnos returned from host to vxWorks' errnos
  913. *
  914. * This routine maps from the portable errno values defined in wdb.h for
  915. * the TSFS, to errnos defined on the target.  All POSIX errnos are passed
  916. * through this mapping without change.  WDB-specific errnos that have been
  917. * returned from the host are also not mapped.
  918. *
  919. * INTERNAL
  920. * Errnos that are not defined as portable.  This includes POSIX errnos, but
  921. * is may include more if some get through the cracks.
  922. *
  923. * RETURNS:  vxWorks' errno, or zero (0) if passed zero (0) 
  924. *         
  925. * NOMANUAL
  926. */
  927. static int tsfsErrnoMap
  928.     (
  929.     int hostErrno /* non-vxWorks errno returned from host */
  930.     )
  931.     {
  932.     int wverr;
  933.     /*
  934.      * By default pass on the error because it may be a POSIX errno.  It may
  935.      * also be zero, so it shouldn't get modified.  Unknown errnos will pass
  936.      * right through.  There should be no default case in the switch below.
  937.      */
  938.     wverr = hostErrno;
  939.     switch (hostErrno)
  940. {
  941. case  WDB_TSFS_ERRNO_ENOTEMPTY:        wverr = ENOTEMPTY; break;
  942. case  WDB_TSFS_ERRNO_EDEADLK:          wverr = EDEADLK; break;
  943. case  WDB_TSFS_ERRNO_ENOLCK:           wverr = ENOLCK; break;
  944. case  WDB_TSFS_ERRNO_EMSGSIZE:         wverr = EMSGSIZE; break;
  945. case  WDB_TSFS_ERRNO_EOPNOTSUPP:       wverr = EOPNOTSUPP; break;
  946. case  WDB_TSFS_ERRNO_EADDRNOTAVAIL:    wverr = EADDRNOTAVAIL; break;
  947. case  WDB_TSFS_ERRNO_ENOTSOCK:         wverr = ENOTSOCK; break;
  948. case  WDB_TSFS_ERRNO_ENETRESET:        wverr = ENETRESET; break;
  949. case  WDB_TSFS_ERRNO_ECONNABORTED:     wverr = ECONNABORTED; break;
  950. case  WDB_TSFS_ERRNO_ECONNRESET:       wverr = ECONNRESET; break;
  951. case  WDB_TSFS_ERRNO_ECONNREFUSED:      wverr = ECONNREFUSED; break;
  952. case  WDB_TSFS_ERRNO_ENOBUFS:          wverr = ENOBUFS; break;
  953. case  WDB_TSFS_ERRNO_ENOTCONN:         wverr = ENOTCONN; break;
  954. case  WDB_TSFS_ERRNO_ESHUTDOWN:        wverr = ESHUTDOWN; break;
  955. case  WDB_TSFS_ERRNO_ETIMEDOUT:        wverr = ETIMEDOUT; break;
  956. case  WDB_TSFS_ERRNO_EINPROGRESS:      wverr = EINPROGRESS; break;
  957. case  WDB_TSFS_ERRNO_EWOULDBLOCK:       wverr = EWOULDBLOCK; break;
  958. case  WDB_TSFS_ERRNO_ENOSR:            wverr = ENOSR; break;
  959. case  WDB_TSFS_ERRNO_ELOOP:            wverr = ELOOP; break;
  960. case  WDB_TSFS_ERRNO_ENAMETOOLONG:     wverr = ENAMETOOLONG; break;
  961. case  WDB_TSFS_ERRNO_EBADMSG:          wverr = EBADMSG; break;
  962. }
  963.     return (wverr);
  964.     }
  965. /******************************************************************************
  966. *
  967. * tsfsEventGet - fill in WDB event parameters at transmission time
  968. * RETURNS: N/A
  969. * NOMANUAL
  970. */
  971. static void tsfsEventGet
  972.     (
  973.     void * arg,
  974.     WDB_EVT_DATA *  pEvtData
  975.     )
  976.     {
  977.     TSFS_CHANNEL_DESC * pChannel = (TSFS_CHANNEL_DESC *) arg;
  978.     int size;
  979.     size = sizeof (WDB_TSFS_GENERIC_INFO);
  980.     switch (pChannel->info.info.opcode)
  981. {
  982. case WDB_TSFS_OPEN:
  983.     size += sizeof (WDB_TSFS_OPEN_INFO);
  984.     break;
  985. case WDB_TSFS_DELETE:
  986.     size += sizeof (WDB_TSFS_DELETE_INFO);
  987.     break;
  988. case WDB_TSFS_WRITE:
  989. case WDB_TSFS_READ:
  990.     size += sizeof (WDB_TSFS_RW_INFO);
  991.     break;
  992. case WDB_TSFS_IOCTL:
  993.     size += sizeof (WDB_TSFS_IOCTL_INFO);
  994.     break;
  995. case WDB_TSFS_CLOSE:
  996. default:
  997.     break;
  998. };
  999.     memcpy (&pEvtData->eventInfo, &pChannel->info, size);
  1000.     pEvtData->evtType = WDB_EVT_TSFS_OP;
  1001.     pEvtData->eventInfo.evtInfo.numInts = size / sizeof (TGT_INT_T) - 1;
  1002.     }
  1003. /******************************************************************************
  1004. *
  1005. * tsfsEventDeq - free allocated event data after transmission
  1006. *
  1007. * NOMANUAL
  1008. */
  1009. static void tsfsEventDeq
  1010.     (
  1011.     void * arg
  1012.     )
  1013.     {
  1014.     /* The tsfs event has no allocated data or other need for cleanup. */
  1015.     return;
  1016.     }