ptyDrv.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:16k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* ptyDrv.c - pseudo-terminal driver */
  2. /* Copyright 1984-2001 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01z,12oct01,brk  added SELECT functionality to Master (SPR #65498) 
  8. 01y,19oct01,dcb  Fix the routine title line to match the coding conventions.
  9. 01x,14feb01,spm  merged from version 01x of tor2_0_x branch (base 01w):
  10.                  added removal of pty device (SPR #28675)
  11. 01w,12mar99,p_m  Fixed SPR 9124 by mentioning that there is no way to delete a
  12.                  pty device.
  13. 01v,03feb93,jdi  documentation cleanup for 5.1.
  14. 01u,13nov92,dnw  added include of semLibP.h
  15. 01t,21oct92,jdi  removed mangen SECTION designation.
  16. 01s,18jul92,smb  Changed errno.h to errnoLib.h.
  17. 01r,04jul92,jcf  scalable/ANSI/cleanup effort.
  18. 01q,26may92,rrr  the tree shuffle
  19. 01p,19nov91,rrr  shut up some ansi warnings.
  20. 01o,04oct91,rrr  passed through the ansification filter
  21.                   -changed functions to ansi style
  22.   -changed includes to have absolute path from h/
  23.   -changed VOID to void
  24.   -changed copyright notice
  25. 01n,05apr91,jdi  documentation -- removed header parens and x-ref numbers;
  26.  doc review by rdc.
  27. 01m,27feb91,jaa  documentation update.
  28. 01l,26jun90,jcf  changed semaphore type for 5.0.  Embedded semaphore.
  29. 01k,23mar90,dab  removed ptyMasterDelete() and ptySlaveDelete().
  30. 01j,15feb90,dab  added ptyMasterDelete() and ptySlaveDelete(). documentation.
  31. 01i,30may88,dnw  changed to v4 names.
  32. 01h,04may88,jcf  changed semaphores to be consistent with new semLib.
  33. 01g,06nov87,ecs  documentation.
  34. 01f,24oct87,gae  added pty{Master,Slave}Close() so that reads on
  35.    corresponding would return 0/ERROR.
  36. 01e,20oct87,gae  made ptyDrv() return correct status on succesive calls.
  37.  documentation.
  38. 01d,25mar87,jlf  documentation
  39. 01c,21dec86,dnw  changed to not get include files from default directories.
  40. 01b,02jul86,jlf  documentation
  41. 01a,01apr86,rdc  wrotten.
  42. */
  43. /*
  44. The pseudo-terminal driver provides a tty-like interface between a master and
  45. slave process, typically in network applications.  The master process
  46. simulates the "hardware" side of the driver (e.g., a USART serial chip), while
  47. the slave process is the application program that normally talks to the driver.
  48. USER-CALLABLE ROUTINES
  49. Most of the routines in this driver are accessible only through the I/O
  50. system.  However, the following routines must be called directly: ptyDrv() to
  51. initialize the driver, ptyDevCreate() to create devices, and ptyDevRemove()
  52. to remove an existing device.
  53. INITIALIZING THE DRIVER
  54. Before using the driver, it must be initialized by calling ptyDrv().
  55. This routine must be called before any reads, writes, or calls to
  56. ptyDevCreate().
  57. CREATING PSEUDO-TERMINAL DEVICES
  58. Before a pseudo-terminal can be used, it must be created by calling
  59. ptyDevCreate():
  60. .CS
  61.     STATUS ptyDevCreate
  62. (
  63. char  *name,   /@ name of pseudo terminal      @/
  64. int   rdBufSize,  /@ size of terminal read buffer @/
  65. int   wrtBufSize  /@ size of write buffer         @/
  66. )
  67. .CE
  68. For instance, to create the device pair "/pty/0.M" and "/pty/0.S",
  69. with read and write buffer sizes of 512 bytes, the proper call would be:
  70. .CS
  71.    ptyDevCreate ("/pty/0.", 512, 512);
  72. .CE
  73. When ptyDevCreate() is called, two devices are created, a master and
  74. slave.  One is called <name>M and the other <name>S.  They can
  75. then be opened by the master and slave processes.  Data written to the
  76. master device can then be read on the slave device, and vice versa.  Calls
  77. to ioctl() may be made to either device, but they should only apply to the
  78. slave side, since the master and slave are the same device.
  79. The ptyDevRemove() routine will delete an existing pseudo-terminal device
  80. and reclaim the associated memory. Any file descriptors associated with
  81. the device will be closed.
  82. IOCTL FUNCTIONS
  83. Pseudo-terminal drivers respond to the same ioctl() functions used by
  84. tty devices.  These functions are defined in ioLib.h and documented in
  85. the manual entry for tyLib.
  86. INCLUDE FILES: ioLib.h, ptyDrv.h
  87. SEE ALSO: tyLib,
  88. .pG "I/O System"
  89. */
  90. #include "vxWorks.h"
  91. #include "ioLib.h"
  92. #include "iosLib.h"
  93. #include "semLib.h"
  94. #include "stdlib.h"
  95. #include "wdLib.h"
  96. #include "selectLib.h"
  97. #include "tyLib.h"
  98. #include "ptyDrv.h"
  99. #include "string.h"
  100. #include "errnoLib.h"
  101. #include "private/semLibP.h"
  102. #include "private/funcBindP.h" 
  103. IMPORT STATUS tyDevRemove(TY_DEV_ID pTyDev);
  104. #define PTY_WRITE_THRESHOLD 20
  105. /* local variables */
  106. LOCAL int ptySlaveDrvNum; /* driver number assigned to slave driver */
  107. LOCAL int ptyMasterDrvNum; /* driver number assigned to master drv */
  108. LOCAL int ptyWrtThreshold  = PTY_WRITE_THRESHOLD;
  109.  /* min bytes free in output buffer */
  110. /* forward static functions */
  111. static int ptyMasterOpen (PSEUDO_DEV *pPseudoDev, char *name, int mode); 
  112. static int ptySlaveOpen (PSEUDO_DEV *pPseudoDev, char *name, int mode);
  113. static STATUS ptySlaveClose (PSEUDO_DEV *pPseudoDev);
  114. static STATUS ptyMasterClose (PSEUDO_DEV *pPseudoDev);
  115. static int ptySlaveRead (PSEUDO_DEV *pPseudoDev, char *buffer, int maxbytes);
  116. static int ptyMasterRead (PSEUDO_DEV *pPseudoDev, char *buffer, int
  117. maxbytes);
  118. static int ptySlaveWrite (PSEUDO_DEV *pPseudoDev, char *buffer, int nbytes);
  119. static int ptyMasterWrite (PSEUDO_DEV *pPseudoDev, char *buffer, int nbytes);
  120. static STATUS ptySlaveIoctl (PSEUDO_DEV *pPseudoDev, int request, int arg);
  121. static STATUS ptyMasterIoctl (PSEUDO_DEV *pPseudoDev, int request, int arg);
  122. static void ptyMasterStartup (PSEUDO_DEV *pPseudoDev);
  123. /*******************************************************************************
  124. *
  125. * ptyDrv - initialize the pseudo-terminal driver
  126. *
  127. * This routine initializes the pseudo-terminal driver.
  128. * It must be called before any other routine in this module.
  129. *
  130. * RETURNS: OK, or ERROR if the master or slave devices cannot be installed.
  131. */
  132. STATUS ptyDrv (void)
  133.     {
  134.     static BOOL done; /* FALSE = not done, TRUE = done */
  135.     static STATUS status;
  136.     if (!done)
  137. {
  138. done = TRUE;
  139. ptySlaveDrvNum = iosDrvInstall (ptySlaveOpen, (FUNCPTR) NULL,
  140. ptySlaveOpen, ptySlaveClose,
  141. ptySlaveRead, ptySlaveWrite,
  142. ptySlaveIoctl);
  143. ptyMasterDrvNum = iosDrvInstall (ptyMasterOpen, (FUNCPTR) NULL,
  144. ptyMasterOpen, ptyMasterClose,
  145. ptyMasterRead, ptyMasterWrite,
  146. ptyMasterIoctl);
  147. status = (ptySlaveDrvNum != ERROR && ptyMasterDrvNum != ERROR) ? OK
  148.        : ERROR;
  149. }
  150.     return (status);
  151.     }
  152. /*******************************************************************************
  153. *
  154. * ptyDevCreate - create a pseudo terminal
  155. *
  156. * This routine creates a master and slave device which can then be opened by
  157. * the master and slave processes.  The master process simulates the "hardware"
  158. * side of the driver, while the slave process is the application program that
  159. * normally talks to a tty driver.   Data written to the master device can then
  160. * be read on the slave device, and vice versa.
  161. *
  162. * RETURNS: OK, or ERROR if memory is insufficient.
  163. */
  164. STATUS ptyDevCreate
  165.     (
  166.     char *name,         /* name of pseudo terminal */
  167.     int rdBufSize,      /* size of terminal read buffer */
  168.     int wrtBufSize      /* size of write buffer */
  169.     )
  170.     {
  171.     STATUS status;
  172.     char nameBuf [MAX_FILENAME_LENGTH];
  173.     PSEUDO_DEV *pPseudoDev;
  174.     if (ptySlaveDrvNum < 1 || ptyMasterDrvNum < 1)
  175. {
  176. errnoSet (S_ioLib_NO_DRIVER);
  177. return (ERROR);
  178. }
  179.     pPseudoDev = (PSEUDO_DEV *) malloc (sizeof (PSEUDO_DEV));
  180.     if (pPseudoDev == NULL)
  181. return (ERROR);
  182.     /* initialize device descriptor */
  183.     if (tyDevInit ((TY_DEV_ID) pPseudoDev, rdBufSize, wrtBufSize,
  184.    (FUNCPTR)ptyMasterStartup) != OK)
  185. {
  186. free ((char *)pPseudoDev);
  187. return (ERROR);
  188. }
  189.     /* initialize the select stuff for the master pty fd */
  190.     if (_func_selWakeupListInit != NULL)
  191.         (* _func_selWakeupListInit) (&pPseudoDev->masterSelWakeupList);
  192.     semBInit (&pPseudoDev->masterReadSyncSem, SEM_Q_PRIORITY, SEM_EMPTY);
  193.     /* add Slave and Master devices */
  194.     strcpy (nameBuf, name);
  195.     strcat (nameBuf, "S");
  196.     status = iosDevAdd (&pPseudoDev->slaveDev, nameBuf, ptySlaveDrvNum);
  197.     if (status == OK)
  198. {
  199. strcpy (nameBuf, name);
  200. strcat (nameBuf, "M");
  201. status = iosDevAdd ((DEV_HDR *) pPseudoDev, nameBuf, ptyMasterDrvNum);
  202. }
  203.     return (status);
  204.     }
  205. /******************************************************************************
  206. *
  207. * ptyDevRemove - destroy a pseudo terminal
  208. *
  209. * This routine removes an existing master and slave device and releases all
  210. * allocated memory. It will close any open files using either device.
  211. *
  212. * RETURNS: OK, or ERROR if terminal not found
  213. *
  214. * INTERNAL
  215. * This routine reverses the ptyDevCreate() routine operations.
  216. */
  217. STATUS ptyDevRemove
  218.     (
  219.     char *  pName         /* name of pseudo terminal to remove */
  220.     )
  221.     {
  222.     char *  pTail = NULL;  /* Pointer to tail of device name. */
  223.     DEV_HDR *  pMasterDev;
  224.     DEV_HDR *  pSlaveDev;
  225.     char nameBuf [MAX_FILENAME_LENGTH];
  226.     PSEUDO_DEV *pPseudoDev;
  227.     if (ptySlaveDrvNum < 1 || ptyMasterDrvNum < 1)
  228.         {
  229.         errnoSet (S_ioLib_NO_DRIVER);
  230.         return (ERROR);
  231.         }
  232.     strcpy (nameBuf, pName);
  233.     strcat (nameBuf, "M");
  234.     pMasterDev = iosDevFind (nameBuf, &pTail);
  235.     if (pMasterDev == NULL || pTail == nameBuf)     /* Device not found? */
  236.         return (ERROR);
  237.     strcpy (nameBuf, pName);
  238.     strcat (nameBuf, "S");
  239.     pSlaveDev = iosDevFind (nameBuf, &pTail);
  240.     if (pSlaveDev == NULL || pTail == nameBuf)      /* Device not found? */
  241.         return (ERROR);
  242.     /* Close any open files and remove the master and slave devices. */
  243.     iosDevDelete (pSlaveDev);
  244.     iosDevDelete (pMasterDev);
  245.     /*
  246.      * The master device header is also the header for the ty device and
  247.      * a pointer to the overall pseudo device structure. Remove those
  248.      * data structures.
  249.      */
  250.     pPseudoDev = (PSEUDO_DEV *)pMasterDev;
  251.     tyDevRemove ( (TY_DEV_ID)pMasterDev);
  252.     free (pPseudoDev);
  253.     return (OK);
  254.     }
  255. /*******************************************************************************
  256. *
  257. * ptyMasterOpen - open the Master side of a pseudo terminal
  258. *
  259. * ARGSUSED1
  260. */
  261. LOCAL int ptyMasterOpen
  262.     (
  263.     PSEUDO_DEV *pPseudoDev,
  264.     char *name,
  265.     int mode
  266.     )
  267.     {
  268.     return ((int) pPseudoDev);
  269.     }
  270. /*******************************************************************************
  271. *
  272. * ptySlaveOpen - open the Slave side of a pseudo terminal
  273. *
  274. * ARGSUSED1
  275. */
  276. LOCAL int ptySlaveOpen
  277.     (
  278.     PSEUDO_DEV *pPseudoDev,
  279.     char *name,
  280.     int mode
  281.     )
  282.     {
  283.     return ((int) pPseudoDev - (OFFSET(PSEUDO_DEV, slaveDev)));
  284.     }
  285. /*******************************************************************************
  286. *
  287. * ptySlaveClose - close the Slave side of a pseudo terminal
  288. *
  289. * Closing the slave side should cause the master to read 0 bytes.
  290. *
  291. * RETURNS: OK
  292. */
  293. LOCAL STATUS ptySlaveClose
  294.     (
  295.     PSEUDO_DEV *pPseudoDev
  296.     )
  297.     {
  298.     pPseudoDev->ateof = FALSE; /* indicate to master read of close */
  299.     semGive (&pPseudoDev->masterReadSyncSem);
  300.  
  301.     if(_func_selWakeupAll != NULL) 
  302.      {
  303.      /* wake up any process waiting so they read the 0 bytes */
  304. (* _func_selWakeupAll) (&pPseudoDev->masterSelWakeupList, SELREAD);
  305.      }
  306.     return (OK);
  307.     }
  308. /*******************************************************************************
  309. *
  310. * ptyMasterClose - close the Master side of a pseudo terminal
  311. *
  312. * Closing the master side will cause the slave's read to return ERROR.
  313. *
  314. * RETURNS: OK
  315. */
  316. LOCAL STATUS ptyMasterClose
  317.     (
  318.     PSEUDO_DEV *pPseudoDev
  319.     )
  320.     {
  321.     tyIoctl ((TY_DEV_ID) pPseudoDev, FIOCANCEL, 0 /*XXX*/);
  322.     return (OK);
  323.     }
  324. /*******************************************************************************
  325. *
  326. * ptySlaveRead - slave read routine
  327. *
  328. * The slave device simply calls tyRead to get data out of the ring buffer.
  329. *
  330. * RETURNS: whatever tyRead returns (number of bytes actually read)
  331. */
  332. LOCAL int ptySlaveRead
  333.     (
  334.     PSEUDO_DEV *pPseudoDev,
  335.     char *buffer,
  336.     int maxbytes
  337.     )
  338.     {
  339.     int i;
  340.     i=tyRead ((TY_DEV_ID) pPseudoDev, buffer, maxbytes);
  341.     if (_func_selWakeupAll != NULL) 
  342.      {
  343.      /* When anything gets read from the slave and the buffer is below
  344.          * the threshhold wake processes waiting
  345.          * on SELWRITE of master pty fd 
  346.          */
  347.   if (rngNBytes (pPseudoDev->tyDev.rdBuf) < ptyWrtThreshold )  
  348.      (* _func_selWakeupAll) (&pPseudoDev->masterSelWakeupList, SELWRITE );
  349.      }
  350.     return(i); 
  351.     }
  352. /*******************************************************************************
  353. *
  354. * ptyMasterRead - master read routine
  355. *
  356. * The master read routine calls tyITx to empty the pseudo terminal's buffer.
  357. *
  358. * RETURNS: number of characters actually read
  359. */
  360. LOCAL int ptyMasterRead
  361.     (
  362.     PSEUDO_DEV *pPseudoDev,
  363.     char *buffer,               /* where to return characters read */
  364.     int maxbytes
  365.     )
  366.     {
  367.     int i;
  368.     char ch;
  369.     pPseudoDev->ateof = TRUE;
  370.     for (i = 0; i == 0;)
  371. {
  372. while ((i < maxbytes) && (tyITx ((TY_DEV_ID) pPseudoDev, &ch) == OK))
  373.     buffer [i++] = ch;
  374. if (!pPseudoDev->ateof)
  375.     break;
  376. if (i == 0)
  377.     semTake (&pPseudoDev->masterReadSyncSem, WAIT_FOREVER);
  378. }
  379.     
  380.     return (i);
  381.     }
  382. /*******************************************************************************
  383. *
  384. * ptySlaveWrite - pseudo terminal Slave write routine
  385. *
  386. * This routine simply calls tyWrite.
  387. *
  388. * RETURNS: whatever tyWrite returns (number of bytes actually written)
  389. */
  390. LOCAL int ptySlaveWrite
  391.     (
  392.     PSEUDO_DEV *pPseudoDev,
  393.     char *buffer,
  394.     int nbytes
  395.     )
  396.     {
  397.     int written;
  398.      
  399.     written = tyWrite ((TY_DEV_ID) pPseudoDev, buffer, nbytes);
  400.     
  401.     if(_func_selWakeupAll != NULL) 
  402.      {
  403.      /* When anything gets written to the slave wake processes waiting
  404.          * on SELREAD of master pty fd 
  405.          */
  406.   if(rngNBytes(pPseudoDev->tyDev.wrtBuf))   
  407. (* _func_selWakeupAll) (&pPseudoDev->masterSelWakeupList, SELREAD);
  408.      }
  409.     return(written);
  410.     }
  411. /*******************************************************************************
  412. *
  413. * ptyMasterWrite - pseudo terminal Master write routine
  414. *
  415. * This routine calls tyIRd to put data in the pseudo terminals ring buffer.
  416. *
  417. * RETURNS: nbytes
  418. */
  419. LOCAL int ptyMasterWrite
  420.     (
  421.     PSEUDO_DEV *pPseudoDev,
  422.     char *buffer,
  423.     int nbytes
  424.     )
  425.     {
  426.     int i;
  427.     for (i = 0; i < nbytes; i++)
  428. (void)tyIRd ((TY_DEV_ID) pPseudoDev, buffer [i]);
  429.      return (i);
  430.     }
  431. /*******************************************************************************
  432. *
  433. * ptySlaveIoctl - special device control
  434. */
  435. LOCAL STATUS ptySlaveIoctl
  436.     (
  437.     PSEUDO_DEV *pPseudoDev,     /* device to control */
  438.     int request,                /* request code */
  439.     int arg                     /* some argument */
  440.     )
  441.     {
  442.     return (tyIoctl ((TY_DEV_ID) pPseudoDev, request, arg));
  443.     }
  444. /*******************************************************************************
  445. *
  446. * ptyMasterIoctl - special device control
  447. */
  448. LOCAL STATUS ptyMasterIoctl
  449.     (
  450.     PSEUDO_DEV *pPseudoDev,     /* device to control */
  451.     int request,                /* request code */
  452.     int arg                     /* some argument */
  453.     )
  454.     {
  455. switch (request)
  456. {
  457.    case FIOSELECT:
  458. if ( _func_selPtyAdd != NULL )
  459.     _func_selPtyAdd(pPseudoDev, arg);  
  460. break;
  461.            case FIOUNSELECT:
  462. if ( _func_selPtyDelete != NULL )
  463.     _func_selPtyDelete(pPseudoDev, arg);  
  464. break;
  465.    default:
  466.      return (tyIoctl ((TY_DEV_ID) pPseudoDev, request, arg));
  467. }
  468. return(OK);
  469.     }
  470. /*******************************************************************************
  471. *
  472. * ptyMasterStartup - start up the Master read routine
  473. */
  474. LOCAL void ptyMasterStartup
  475.     (
  476.     PSEUDO_DEV *pPseudoDev
  477.     )
  478.     {
  479.     semGive (&pPseudoDev->masterReadSyncSem);
  480.     }
  481. #undef PTY_DEBUG
  482. #ifdef PTY_DEBUG
  483. extern DL_LIST  iosDvList; /* list of I/O device headers */
  484. /*******************************************************************************
  485. *
  486. *  ptyShow - show the state of the Pty Buffers 
  487. */
  488. void ptyShow(void)
  489. {
  490.     PSEUDO_DEV *pDevHdr;
  491.     int rd,wrt;
  492.     logMsg("%-20s %-8s %-8sn", "name","read","write",0,0,0);
  493.     for (pDevHdr = (PSEUDO_DEV *) DLL_FIRST (&iosDvList); pDevHdr != NULL;
  494. pDevHdr = (PSEUDO_DEV *) DLL_NEXT (&pDevHdr->tyDev.devHdr.node))
  495.     {
  496.         if( pDevHdr->tyDev.devHdr.drvNum == ptyMasterDrvNum )
  497. {
  498. rd = rngNBytes (pDevHdr->tyDev.rdBuf);
  499. wrt = rngNBytes (pDevHdr->tyDev.wrtBuf);
  500. logMsg("%-20s %-8d %-8dn", pDevHdr->tyDev.devHdr.name, wrt,rd,0,0,0);
  501. }
  502.      }
  503. }
  504. #endif