/*	
 *	app.h
 *
 *	PceCom - P/ECE USBシリアルポートデバイスドライバ
 *	Copyright (C) 2005 Naoyuki Sawa
 *
 *	* Wed Aug 03 21:57:00 JST 2005 Naoyuki Sawa
 *	- 1st リリース。
 */
#ifndef __APP_H__
#define __APP_H__

#include "util.h"

#define QUIET

/****************************************************************************
 *
 ****************************************************************************/

///* {C338FFCC-63F5-4445-92C6-5DCE96065258} */
//DEFINE_GUID(PCECOM_GUID,0xC338FFCC,0x63F5,0x4445,0x92,0xC6,0x5D,0xCE,0x96,0x06,0x52,0x58);
//→デバイスインターフェイスでなく、明示的なデバイス名とシンボリックリンクを使っているので、
//  デバイスインターフェイスを登録するためのGUIDは必要ありません。(2005/07/27現在)

typedef struct _DEVICE_EXTENSION {
	DEVICE_OBJECT* device_object;
	DEVICE_OBJECT* next_device_object;
	DEVICE_OBJECT* physical_device_object;
	//
	UNICODE_STRING device_name;
	wchar_t _device_name[64];
	//
	KEVENT terminate_event;
	void* serialcomm;
	//
	/*---------- RX ----------*/
	USBD_PIPE_INFORMATION rx_pipe;
	KEVENT rx_event_to_process;
	KEVENT rx_event_to_polling;
	//
	unsigned char* rx_buffer/*[rx_capacity]*/;
	int rx_capacity;
	int rx_length;
	//
	LIST_ENTRY rx_queue;
	IRP* rx_current_irp;
	PKTHREAD rx_process_thread;
	PKTHREAD rx_polling_thread;

	/*---------- TX ----------*/
	USBD_PIPE_INFORMATION tx_pipe;
	KEVENT tx_event_to_process;
	KEVENT tx_event_to_polling;
	//
	unsigned char* tx_buffer/*[tx_capacity]*/;
	int tx_capacity;
	int tx_length;
	//
	LIST_ENTRY tx_queue;
	IRP* tx_current_irp;
	PKTHREAD tx_process_thread;
	PKTHREAD tx_polling_thread;

	/*---------- IOCTL ----------*/
	SERIAL_QUEUE_SIZE queue_size;
	SERIAL_COMMPROP properties;
	SERIAL_STATUS comm_status;
	int modem_status;
	int dtr_rts;
	SERIAL_LINE_CONTROL line_control;
	SERIAL_BAUD_RATE baud_rate;
	SERIAL_HANDFLOW handflow;
	SERIAL_TIMEOUTS timeouts;
	SERIAL_CHARS chars;
	SERIALPERF_STATS stats;
	//
	int wait_mask;
	int comm_event;
	IRP* wait_on_mask_irp;

} DEVICE_EXTENSION;

/****************************************************************************
 *
 ****************************************************************************/

/* * キャンセルスピンロックを、本来のキャンセルスピンロックとしてだけでなく、
 *   デバイスドライバ全体の共通スピンロックとして利用することにします。
 * - 複数のスピンロックを使うことによるデッドロックを避け、実装を簡単にするための暫定措置です。
 *   本当は、無用な性能低下を防ぐために、複数のスピンロックを用意するべきです。
 */
#define ENTER_CS	{ KIRQL __irql__; IoAcquireCancelSpinLock(&__irql__);
#define LEAVE_CS	                  IoReleaseCancelSpinLock( __irql__); }

/* main.c */
void driver_unload(DRIVER_OBJECT* driver_object);
NTSTATUS add_device(DRIVER_OBJECT* driver_object, DEVICE_OBJECT* physical_device_object);
NTSTATUS dispatch_pnp(DEVICE_OBJECT* device_object, IRP* irp);
NTSTATUS dispatch_power(DEVICE_OBJECT* device_object, IRP* irp);
NTSTATUS dispatch_create(DEVICE_OBJECT* device_object, IRP* irp);
NTSTATUS dispatch_close(DEVICE_OBJECT* device_object, IRP* irp);
NTSTATUS call_next_driver(DEVICE_OBJECT* device_object, IRP* irp);
void stop_device(DEVICE_OBJECT* device_object);
NTSTATUS exec_transfer(DEVICE_OBJECT* device_object, URB* urb);

/* ioctl.c */
NTSTATUS ioctl_init(DEVICE_OBJECT* device_object);
void ioctl_exit(DEVICE_OBJECT* device_object);
NTSTATUS dispatch_ioctl(DEVICE_OBJECT* device_object, IRP* irp);
void complete_wait_on_mask(IRP* irp, int wait_mask);
void assert_comm_event(DEVICE_OBJECT* device_object, int comm_event);

/* rx.c */
NTSTATUS rx_init(DEVICE_OBJECT* device_object);
void rx_exit(DEVICE_OBJECT* device_object);
NTSTATUS dispatch_rx(DEVICE_OBJECT* device_object, IRP* irp);
NTSTATUS rx_resize(DEVICE_OBJECT* device_object, int capacity);
void rx_abort(DEVICE_OBJECT* device_object);

/* tx.c */
NTSTATUS tx_init(DEVICE_OBJECT* device_object);
void tx_exit(DEVICE_OBJECT* device_object);
NTSTATUS dispatch_tx(DEVICE_OBJECT* device_object, IRP* irp);
NTSTATUS tx_resize(DEVICE_OBJECT* device_object, int capacity);
void tx_abort(DEVICE_OBJECT* device_object);

/****************************************************************************
 *
 ****************************************************************************/

#endif /*__APP_H__*/
