* drv/pty.c
* - Pseudo Terminals
*/
+#define DEBUG 0
#include <acess.h>
#include <vfs.h>
#include <fs_devfs.h>
void *OutputHandle;
tPTY_OutputFcn OutputFcn;
tPTY_ReqResize ReqResize;
+ tPTY_ModeSet ModeSet;
struct ptymode Mode;
struct ptydims Dims;
.Name = "pts",
.RootNode = {
.Flags = VFS_FFLAG_DIRECTORY,
- .Type = &gPTY_NodeType_Root
+ .Type = &gPTY_NodeType_Root,
+ .Size = -1
}
};
int giPTY_NumCount;
// === CODE ===
int PTY_Install(char **Arguments)
{
+ DevFS_AddDevice(&gPTY_Driver);
return MODULE_ERR_OK;
}
// --- Management ---
-tPTY *PTY_Create(const char *Name, void *Handle, tPTY_OutputFcn Output, tPTY_ReqResize ReqResize)
+tPTY *PTY_Create(const char *Name, void *Handle, tPTY_OutputFcn Output, tPTY_ReqResize ReqResize, tPTY_ModeSet ModeSet)
{
tPTY **prev_np = NULL;
size_t namelen;
ret->OutputHandle = Handle;
ret->OutputFcn = Output;
ret->ReqResize = ReqResize;
+ ret->ModeSet = ModeSet;
// - Server node
ret->ServerNode.ImplPtr = ret;
ret->ServerNode.Type = &gPTY_NodeType_Server;
errno = EINVAL;
return -1;
}
- PTY->Mode = *Mode;
- if( !WasClient && !PTY->OutputFcn )
+ if( WasClient )
{
- Log_Warning("PTY", "TODO: Need to stop client output until modeset has been ACKed");
- // Block write until acked
- // ACK by server doing GETMODE
+ if( PTY->ModeSet && PTY->ModeSet(PTY->OutputHandle, Mode) )
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ else if( !PTY->OutputFcn )
+ {
+ Log_Warning("PTY", "TODO: Need to stop client output until modeset has been ACKed");
+ // Block write until acked
+ // ACK by server doing GETMODE
+ }
}
+ else
+ {
+ // Should the client be informed that the server just twiddled the modes?
+ }
+ LOG("PTY %p mode set to {0%o, 0%o}", PTY, Mode->InputMode, Mode->OutputMode);
+ PTY->Mode = *Mode;
}
if( Dims )
{
- if( WasClient ) {
+ if( WasClient )
+ {
// Poke the server?
if( PTY->ReqResize && PTY->ReqResize(PTY->OutputHandle, Dims) )
{
// Inform server process... somehow
}
}
- else {
+ else
+ {
// SIGWINSZ to client
}
+ LOG("PTY %p dims set to %ix%i", PTY, Dims->W, Dims->H);
PTY->Dims = *Dims;
}
return 0;
size_t _rb_write(void *buf, size_t buflen, int *rd, int *wr, const void *data, size_t len)
{
- size_t space = (*rd - *wr + buflen) % buflen - 1;
+ size_t space = (*rd - *wr + buflen - 1) % buflen;
+ ENTER("pbuf ibuflen prd pwr pdata ilen", buf, buflen, rd, wr, data, len);
len = MIN(space, len);
+ LOG("space = %i, *rd = %i, *wr = %i", space, *rd, *wr);
if(*wr + len >= buflen) {
size_t prelen = buflen - *wr;
memcpy((char*)buf + *wr, data, prelen);
memcpy((char*)buf + *wr, data, len);
*wr += len;
}
+ LEAVE('i', len);
return len;
}
size_t _rb_read(void *buf, size_t buflen, int *rd, int *wr, void *data, size_t len)
{
size_t ret = 1, print = 1;
- // Only counts for text input modes
- if( (PTY->Mode.OutputMode & PTYOMODE_BUFFMT) == PTYBUFFMT_TEXT )
+ // Input mode stuff only counts for text output mode
+ // - Any other is Uint32 keypresses
+ if( (PTY->Mode.OutputMode & PTYOMODE_BUFFMT) != PTYBUFFMT_TEXT )
return PTY_int_WriteInput(PTY, Input, Length);
// If in raw mode, flush directlr
if( (PTY->Mode.InputMode & PTYIMODE_RAW) )
int PTY_ReadDir(tVFS_Node *Node, int Pos, char Name[FILENAME_MAX])
{
tPTY *pty = NULL;
- if( Pos < giPTY_NumCount * 2 )
+ int idx = Pos;
+ if( idx < giPTY_NumCount * 2 )
{
RWLock_AcquireRead(&glPTY_NumPTYs);
for( pty = gpPTY_FirstNumPTY; pty; pty = pty->Next )
{
- if( Pos < 2 )
+ if( idx < 2 )
break;
- Pos -= 2;
+ idx -= 2;
}
RWLock_Release(&glPTY_NumPTYs);
}
- else if( Pos < (giPTY_NumCount + giPTY_NamedCount) * 2 )
+ else if( idx < (giPTY_NumCount + giPTY_NamedCount) * 2 )
{
+ idx -= giPTY_NumCount*2;
RWLock_AcquireRead(&glPTY_NamedPTYs);
for( pty = gpPTY_FirstNamedPTY; pty; pty = pty->Next )
{
- if( Pos < 2 )
+ if( idx < 2 )
break;
- Pos -= 2;
+ idx -= 2;
}
RWLock_Release(&glPTY_NamedPTYs);
}
- if( !pty )
+ if( !pty ) {
+ LOG("%i out of range", Pos);
return -1;
+ }
if( pty->Name[0] )
- snprintf(Name, 255, "%s%c", pty->Name, (Pos == 0 ? 'c' : 's'));
+ snprintf(Name, FILENAME_MAX, "%s%c", pty->Name, (idx == 0 ? 'c' : 's'));
else
- snprintf(Name, 255, "%i%c", pty->NumericName, (Pos == 0 ? 'c' : 's'));
+ snprintf(Name, FILENAME_MAX, "%i%c", pty->NumericName, (idx == 0 ? 'c' : 's'));
+ LOG("Return '%s'", Name);
return 0;
}
tVFS_Node *PTY_MkNod(tVFS_Node *Node, const char *Name, Uint Mode)
{
// zero-length name means a numbered pty has been requested
- if( Name[0] == '\0' )
+ if( Name[0] == '\0' || (Name[0] == '#' && Name[1] == '\0') )
{
- tPTY *ret = PTY_Create(NULL, NULL, NULL, NULL);
+ tPTY *ret = PTY_Create(NULL, NULL, NULL, NULL, NULL);
if( !ret )
return NULL;
return &ret->ServerNode;
// Otherwise return a named PTY
// TODO: Should the request be for '<name>s' or just '<name>'
- tPTY *ret = PTY_Create(Name, NULL, NULL, NULL);
+ tPTY *ret = PTY_Create(Name, NULL, NULL, NULL, NULL);
if(!ret)
return NULL;
return &ret->ServerNode;
// Write to either FIFO or directly to output function
if( pty->OutputFcn )
{
- pty->OutputFcn(pty->OutputHandle, Buffer, Length, pty->Mode.OutputMode);
+ pty->OutputFcn(pty->OutputHandle, Length, Buffer);
}
else
{
{
case DRV_IOCTL_TYPE: return DRV_TYPE_TERMINAL;
case DRV_IOCTL_IDENT: memcpy(Data, "PTY\0", 4); return 0;
- case DRV_IOCTL_VER: return 0x100;
+ case DRV_IOCTL_VERSION: return 0x100;
case DRV_IOCTL_LOOKUP: return 0;
case PTY_IOCTL_GETMODE:
{
Node->ReferenceCount ++;
// TODO: Add PID to list of client PIDs
- Log_Notice("PTY", "TODO: List of client PIDs");
+// Log_Notice("PTY", "ReferenceClient: TODO - List of client PIDs");
}
void PTY_CloseClient(tVFS_Node *Node)
Node->ReferenceCount --;
// Remove PID from list
+ // TODO: Maintain list of client processes
// Free structure if this was the last open handle
if( Node->ReferenceCount == 0 && pty->ServerNode.ReferenceCount == 0 )
//\! Write to the client's input
size_t PTY_WriteServer(tVFS_Node *Node, off_t Offset, size_t Length, const void *Buffer, Uint Flags)
{
- // Write to current line buffer, flushing on unknown character or newline
- // - or line wrap?
- // Echo back if instructed
- PTY_SendInput(Node->ImplPtr, Buffer, Length);
- return -1;
+ return PTY_SendInput(Node->ImplPtr, Buffer, Length);
}
int PTY_IOCtlServer(tVFS_Node *Node, int ID, void *Data)
{
case DRV_IOCTL_TYPE: return DRV_TYPE_TERMINAL;
case DRV_IOCTL_IDENT: memcpy(Data, "PTY\0", 4); return 0;
- case DRV_IOCTL_VER: return 0x100;
+ case DRV_IOCTL_VERSION: return 0x100;
case DRV_IOCTL_LOOKUP: return 0;
case PTY_IOCTL_GETMODE:
if( !CheckMem(Data, sizeof(*dims)) ) { errno = EINVAL; return -1; }
PTY_SetAttrib(pty, dims, NULL, 0);
break;
+ case PTY_IOCTL_GETID:
+ return pty->NumericName;
}
errno = ENOSYS;
return -1;