Blob Blame History Raw
/*********************************************************/
/*  ptycon: a pty-console bridge                         */
/*  Copyright (C) 2016--2017  SysDeer Technologies, LLC  */
/*  Released under GPLv2 and GPLv3; see COPYING.PTYCON.  */
/*********************************************************/

#include <psxtypes/psxtypes.h>
#include <ntcon/ntcon.h>
#include <ntapi/ntapi.h>
#include <gdi/gdi.h>

#include <ptycon/ptycon.h>
#include "ptycon_driver_impl.h"
#include "ptycon_status_impl.h"

int __stdcall ptyc_console_ctrl(uint32_t);

int __stdcall ptyc_console_reader(void *);
int __stdcall ptyc_console_writer(void *);;
int __stdcall ptyc_console_poller(void *);

int __stdcall ptyc_dbg_cat(struct ptyc_driver_ctx *);
int __stdcall ptyc_dbg_event(void *);
int __stdcall ptyc_dbg_oven(void *);
int __stdcall ptyc_dbg_raw(void *);


struct ptyc_loop_thread_ctx {
	nt_thread_start_routine *	entry;
	struct ptyc_driver_ctx_impl * 	ictx;
};

static int __stdcall ptyc_loop_thread_entry(void * ctx)
{
	struct ptyc_loop_thread_ctx *	xctx;

	xctx = (struct ptyc_loop_thread_ctx *)ctx;

	return ntapi->zw_terminate_thread(
		NT_CURRENT_THREAD_HANDLE,
		xctx->entry(xctx->ictx));
}

static int ptyc_create_loop_thread(
	nt_thread_params *		params,
	struct ptyc_driver_ctx_impl * 	ictx,
	nt_thread_start_routine *	entry)
{
	struct ptyc_loop_thread_ctx	xctx;

	xctx.entry = entry;
	xctx.ictx  = ictx;

	/* rapunzel rapunzel */
	params->hprocess	   = NT_CURRENT_PROCESS_HANDLE;
	params->start		   = ptyc_loop_thread_entry;
	params->ext_ctx		   = &xctx;
	params->ext_ctx_size	   = sizeof(xctx);
	params->stack_size_commit  = 64 * 1024;
	params->stack_size_reserve = 64 * 1024;
	params->creation_flags	   = NT_CREATE_LOCAL_THREAD;

	return ntapi->tt_create_thread(
		params);
}

static int ptyc_free_console_impl(
	struct ptyc_driver_ctx_impl *	ictx,
	int32_t				status)
{
	struct ptyc_term_ctx *		tctx;
	struct ptyc_loop_ctx *		lctx;

	tctx = &ictx->tctx;
	lctx = &ictx->lctx;

	if (tctx->hin)
		ntcon->free_console();

	if (lctx->treader.hthread)
		ntapi->zw_close(lctx->treader.hthread);

	if (lctx->twriter.hthread)
		ntapi->zw_close(lctx->twriter.hthread);

	if (lctx->tpoller.hthread)
		ntapi->zw_close(lctx->tpoller.hthread);

	if (lctx->tdbgevent.hthread)
		ntapi->zw_close(lctx->tdbgevent.hthread);

	if (lctx->tdbgoven.hthread)
		ntapi->zw_close(lctx->tdbgoven.hthread);

	if (lctx->tdbgraw.hthread)
		ntapi->zw_close(lctx->tdbgraw.hthread);

	return status;
}

static int ptyc_init_console(struct ptyc_term_ctx * tctx)
{
	/* console input buffer) */
	if (!(tctx->hin = ntcon->get_std_handle(NT_STD_INPUT_HANDLE)))
		return NT_STATUS_UNSUCCESSFUL;

	/* console screen buffer */
	if (!(tctx->hout = ntcon->create_console_screen_buffer(
			NT_GENERIC_READ | NT_GENERIC_WRITE,
			0,0,NT_CONSOLE_TEXTMODE_BUFFER,0)))
		return NT_STATUS_UNSUCCESSFUL;

	if (!(ntcon->set_console_screen_buffer_size(
			tctx->hout,
			tctx->screen_size)))
		return NT_STATUS_UNSUCCESSFUL;

	if (!(ntcon->set_console_active_screen_buffer(tctx->hout)))
		return NT_STATUS_UNSUCCESSFUL;

	/* console text attributes: default colors */
	if (!(ntcon->set_console_text_attribute(
			tctx->hout,
			NT_BACKGROUND_BLACK | NT_FOREGROUND_WHITE)))
		return NT_STATUS_UNSUCCESSFUL;

	/* console code page: utf-8 */
	if (!(ntcon->set_console_code_page(65001)))
		return NT_STATUS_NOT_SUPPORTED;

	if (!(ntcon->set_console_output_code_page(65001)))
		return NT_STATUS_NOT_SUPPORTED;

	/* input events */
	if (!(ntcon->set_console_mode(
			tctx->hin,
			NT_ENABLE_MOUSE_INPUT
			| NT_ENABLE_WINDOW_INPUT)))
		return NT_STATUS_UNSUCCESSFUL;

	/* ctrl events */
	if (!(ntcon->set_console_ctrl_handler(
			ptyc_console_ctrl,
			true)))
		return NT_STATUS_UNSUCCESSFUL;

	/* cursor info */
	if (!(ntcon->get_console_cursor_info(
			tctx->hout,
			&tctx->cursor_info)))
		return NT_STATUS_UNSUCCESSFUL;

	return NT_STATUS_SUCCESS;
}

int  ptyc_alloc_console(struct ptyc_driver_ctx * dctx)
{
	int32_t				status;
	struct ptyc_driver_ctx_impl *	ictx;
	struct ptyc_term_ctx *		tctx;
	struct ptyc_loop_ctx *		lctx;

	if (!(ictx = ptyc_get_driver_ictx(dctx)))
		return NT_STATUS_INVALID_HANDLE;

	tctx = &ictx->tctx;
	lctx = &ictx->lctx;

	tctx->screen_size.x = 512;
	tctx->screen_size.y = 4096;
	tctx->drvflags      = ictx->cctx.drvflags;

	if (!(ntcon->alloc_console()))
		return NT_STATUS_UNSUCCESSFUL;

	if ((status = ptyc_init_console(tctx)))
		return ptyc_set_status(dctx,status);

	if ((status = ptyc_create_loop_thread(
			&lctx->treader,
			ictx,ptyc_console_reader)))
		return ptyc_set_status(dctx,status);

	if ((status = ptyc_create_loop_thread(
			&lctx->twriter,
			ictx,ptyc_console_writer)))
		return ptyc_set_status(dctx,status);

	if ((status = ptyc_create_loop_thread(
			&lctx->tpoller,
			ictx,ptyc_console_poller)))
		return ptyc_set_status(dctx,status);

	if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_EVENT)
		if ((status = ptyc_create_loop_thread(
				&lctx->tdbgevent,
				ictx,ptyc_dbg_event)))
			return ptyc_set_status(dctx,status);

	if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_OVEN)
		if ((status = ptyc_create_loop_thread(
				&lctx->tdbgoven,
				ictx,ptyc_dbg_oven)))
			return ptyc_set_status(dctx,status);

	if (dctx->cctx->drvflags & PTYC_DRIVER_DBG_RAW)
		if ((status = ptyc_create_loop_thread(
				&lctx->tdbgraw,
				ictx,ptyc_dbg_raw)))
			return ptyc_set_status(dctx,status);

	if ((status = ptyc_dbg_cat(dctx)))
		return ptyc_set_status(dctx,status);

	return ptyc_set_status(dctx,NT_STATUS_SUCCESS);
}


int  ptyc_wait_for_console(struct ptyc_driver_ctx * dctx)
{
	struct ptyc_driver_ctx_impl * ictx;

	if (!(ictx = ptyc_get_driver_ictx(dctx)))
		return NT_STATUS_INVALID_HANDLE;

	return ntapi->zw_wait_for_single_object(
		ictx->lctx.tpoller.hthread,
		NT_SYNC_ALERTABLE,0);
}


void ptyc_free_console(struct ptyc_driver_ctx * dctx)
{
	struct ptyc_driver_ctx_impl * ictx;

	if (!(ictx = ptyc_get_driver_ictx(dctx)))
		return;

	ptyc_free_console_impl(ictx,NT_STATUS_SUCCESS);
}