/*	
 *	adapter.c
 *
 *	PceEth - P/ECE NDIS-WDM ミニポートドライバ
 *	Copyright (C) 2005 Naoyuki Sawa
 *
 *	* Tue Aug 16 06:19:00 JST 2005 Naoyuki Sawa
 *	- 1st リリース。
 */
#include "app.h"

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

MINIPORT_ADAPTER*
create_miniport_adapter(
	NDIS_HANDLE miniport_adapter_handle,
	NDIS_HANDLE wrapper_configuration_context)
{
	static int device_index = -1;
	//
	NTSTATUS status;
	MINIPORT_ADAPTER* miniport_adapter;
	LARGE_INTEGER system_time;
	int user_code;
	unsigned char address[6];
	USBD_PIPE_INFORMATION pipes[2];

	KdPrint(("create_miniport_adapter called\n"));

	/* ホスト/デバイスに割り振るMACアドレスのUserCodeは、システム絶対時刻から生成することにします。
	 * 同じネットワーク上でMACアドレスが重複する可能性は非常に低いと思いますが、
	 * 万一、重複した場合は、P/ECEを抜き差しし、新しいMACアドレスを割り振ることで回避してください。
	 * 2005/08/18現在の実装では、自動的な回避策は採っていません。
	 */
	KeQuerySystemTime(&system_time);
	user_code = (int)(system_time.QuadPart / 10000); /* 100ナノ秒 -> ミリ秒 */

	/* 構造体のメモリを確保します。 */
	miniport_adapter = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_ADAPTER));
	if(miniport_adapter) {
		memset(miniport_adapter, 0, sizeof(MINIPORT_ADAPTER));

		/* ミニポートアダプタハンドルを格納します。 */
		miniport_adapter->miniport_adapter_handle = miniport_adapter_handle;

		/* 共有スピンロックを初期化します。 */
		KeInitializeSpinLock(&miniport_adapter->spin_lock);

		/* 中断通知イベントを初期化します。 */
		KeInitializeEvent(&miniport_adapter->abort_event, NotificationEvent, FALSE);

		/* ホストのMACアドレスを設定します。 */
		address[0] = 2;				/* VendorCode (I/G=0,U/L=1,Vendor=0) */
		address[1] = 0;
		address[2] = 0;
		address[3] = (user_code & ~1) >> 16;	/* UserCode */
		address[4] = (user_code & ~1) >>  8;
		address[5] = (user_code & ~1) >>  0;
		KdPrint(("host   address = %02x-%02x-%02x-%02x-%02x-%02x\n",
			address[0],address[1],address[2],address[3],address[4],address[5]));
		memcpy(miniport_adapter->address, address, 6);

		/* デバイスオブジェクトを取得します。 */
		NdisMGetDeviceProperty(
			miniport_adapter_handle,			/* MiniportAdapterHandle */
			&miniport_adapter->physical_device_object,	/* PhysicalDeviceObject */
			&miniport_adapter->functional_device_object,	/* FunctionalDeviceObject */
			&miniport_adapter->next_device_object,		/* NextDeviceObject */
			NULL,						/* AllocatedResources */
			NULL);						/* AllocatedResourcesTranslated */

		/* コンフィギュレーションを選択します。 */
		if(set_configuration(miniport_adapter->next_device_object, pipes, 2) == 2) {
			miniport_adapter->rx_pipe = pipes[0];
			miniport_adapter->tx_pipe = pipes[1];

			/* デバイスのMACアドレスを設定します。 */
			address[0] = 2;				/* VendorCode (I/G=0,U/L=1,Vendor=0) */
			address[1] = 0;
			address[2] = 0;
			address[3] = (user_code | 1) >> 16;	/* UserCode */
			address[4] = (user_code | 1) >>  8;
			address[5] = (user_code | 1) >>  0;
			KdPrint(("device address = %02x-%02x-%02x-%02x-%02x-%02x\n",
				address[0],address[1],address[2],address[3],address[4],address[5]));
			status = set_device_address(miniport_adapter->next_device_object, address);
			if(NT_SUCCESS(status)) {

				/* 送信処理を初期化します。 */
				status = tx_init(miniport_adapter);
				if(NT_SUCCESS(status)) {

					/* 受信処理を初期化します。 */
					status = rx_init(miniport_adapter);
					if(NT_SUCCESS(status)) {

						/* 全て成功しました。 */
						return miniport_adapter;

					} else {
						KdPrint(("rx_init failed\n"));
					}
					tx_exit(miniport_adapter);
				} else {
					KdPrint(("tx_init failed\n"));
				}
				/* set_device_address()は解除不要 */
			} else {
				KdPrint(("set_device_address failed\n"));
			}
			clear_configuration(miniport_adapter->next_device_object);
		} else {
			KdPrint(("set_configuration failed\n"));
		}
		ExFreePool(miniport_adapter);
		miniport_adapter = NULL;
	} else {
		KdPrint(("ExAllocatePool failed\n"));
	}

	return NULL;
}

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

void
delete_miniport_adapter(
	MINIPORT_ADAPTER* miniport_adapter)
{
	KdPrint(("delete_miniport_adapter called\n"));

	/* 受信処理を終了します。 */
	rx_exit(miniport_adapter);

	/* 送信処理を終了します。 */
	tx_exit(miniport_adapter);

	/* コンフィギュレーションを未選択に戻します。 */
	clear_configuration(miniport_adapter->next_device_object);

	/* 構造体のメモリを開放します。 */
	ExFreePool(miniport_adapter);
}
