//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft shared
// source or premium shared source license agreement under which you licensed
// this source code. If you did not accept the terms of the license agreement,
// you are not authorized to use this source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the SOURCE.RTF on your install media or the root of your tools installation.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//******************************************************************************
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//******************************************************************************
/*++

Module Name:  
    usbserv.h

Abstract:  
    USB driver service class.
    
Notes: 

--*/

#ifndef __USBSERV_H_
#define __USBSERV_H_
#include <usbdi.h>
#include "syncobj.h"
#include "usbclass.h"
#define countof(x) (sizeof(x)/sizeof(*(x)))

#define ERROR_USB_TRANSFER 0x200
typedef struct _CHECK_RESULT {
	DWORD dwTotal;
	DWORD dwSuccess;
	DWORD dwLost;
	DWORD dwJunk;
	DWORD dwSeqError;
} CHECK_RESULT, *LPCHECK_RESULT;

class UsbBasic {
      public:
	UsbBasic(LPCUSB_FUNCS UsbFuncsPtr, LPCUSB_INTERFACE lpInterface, LPCWSTR szUniqueDriverId, LPCUSB_DRIVER_SETTINGS lpDriverSettings);
	~UsbBasic();
	VOID GetUSBDVersion(LPDWORD lpdwMajorVersion, LPDWORD lpdwMinorVersion);
//Helper commands
	BOOL TranslateStringDesc(LPCUSB_STRING_DESCRIPTOR, LPWSTR, DWORD);
	LPCUSB_INTERFACE FindInterface(LPCUSB_DEVICE, UCHAR, UCHAR);
// attribute
	const LPCUSB_FUNCS lpUsbFuncs;
	HKEY OpenClientRegistryKey();
	LPCUSB_INTERFACE GetInterCurface() {
		return lpInterface;
	};
	LPCWSTR GetUniqueDriverId() {
		return szUniqueDriverId;
	};

	void debug(LPCTSTR szFormat, ...);

      private:
	LPUSB_INTERFACE lpInterface;
	LPWSTR szUniqueDriverId;

};

#define MAX_ISOCH_FRAME_LENGTH (0x400*3)
#define LIMITED_UHCI_BLOCK 0x400	//64

class UsbTransfer {
      public:
	UsbTransfer(USB_TRANSFER usbTransfer, LPCUSB_FUNCS lpUsbFuncs, LPVOID lpBuffer = NULL, DWORD dwSize = 0, DWORD dwPhysicalAddr = 0);
	virtual ~ UsbTransfer();
// get info on Transfers
	BOOL IsTransferComplete();
	BOOL IsCompleteNoError();
	BOOL GetTransferStatus(LPDWORD, LPDWORD);
	BOOL GetIsochResults(DWORD, LPDWORD, LPDWORD);
// transfer maniuplators
	BOOL AbortTransfer(DWORD dwFlags = 0);
	BOOL CloseTransfer();
//
	VOID ReInitial(USB_TRANSFER usbTransfer, LPVOID lpBuffer = NULL, DWORD dwSize = 0, DWORD dwPhysicalAddr = 0);
	USB_TRANSFER GetTransferHandle() {
		return hUsbTransfer;
	};
	USB_TRANSFER SetTransferHandle(USB_TRANSFER usbHandle) {
		return (hUsbTransfer = usbHandle);
	}
	virtual void CompleteNotify() {
		transferEvent.SetEvent();
	};
	virtual BOOL WaitForTransferComplete(DWORD dwTicks = INFINITE) {
		return transferEvent.Lock(dwTicks);
	};
	LPVOID SetPipe(LPVOID pPoint) {
		return (lpPipePoint = pPoint);
	};
	LPVOID GetPipe() {
		return lpPipePoint;
	};
	DWORD GetTransferID() {
		return dwID;
	};
	const LPCUSB_FUNCS lpUsbFuncs;
	// Debug Function
	LPVOID GetAttachedBuffer() {
		return lpAttachedBuffer;
	};
	DWORD GetAttachedSize() {
		return dwAttachedSize;
	};
	DWORD GetAttachedPhysicalAddr() {
		return dwAttachedPhysicalAddr;
	};
      private:
	CEvent transferEvent;
	USB_TRANSFER hUsbTransfer;
	LPVOID lpPipePoint;
	DWORD dwID;
	static DWORD dwCurrentID;
	LPVOID lpAttachedBuffer;
	DWORD dwAttachedSize;
	DWORD dwAttachedPhysicalAddr;
};

// define for transfer callback

typedef struct _TransStatus {
	USB_TRANSFER hTransfer;
	LPCUSB_FUNCS lpUsbFuncs;
	BOOL IsFinished;
	CEvent cEvent;
} TransStatus, *PTransStatus;

extern DWORD WINAPI TransferNotify(LPVOID lpvNotifyParameter);


class UsbClass:public UsbBasic {
      public:
	UsbClass(USB_HANDLE usbHandle, LPCUSB_FUNCS UsbFuncsPtr, LPCUSB_INTERFACE lpInterface, LPCWSTR szUniqueDriverId, LPCUSB_DRIVER_SETTINGS lpDriverSettings);
	~UsbClass();

//USB Subsystem Commands
	BOOL GetFrameNumber(LPDWORD);
	BOOL GetFrameLength(LPUSHORT);

//Enables Device to Adjust the USB SOF period on OHCI or UHCI cards
	BOOL TakeFrameLengthControl();
	BOOL SetFrameLength(HANDLE, USHORT);
	BOOL ReleaseFrameLengthControl();

	BOOL DisableDevice(BOOL, BYTE);
	BOOL SuspendDevice(BYTE);
	BOOL ResumeDevice(BYTE);


// Gets info on a device
	LPCUSB_DEVICE GetDeviceInfo();


//Device commands
	USB_TRANSFER IssueVendorTransfer(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD dwFlags, LPCUSB_DEVICE_REQUEST lpControlHeader, LPVOID lpvBuffer, ULONG uBufferPhusicalAddress);
	USB_TRANSFER GetInterface(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD, UCHAR, PUCHAR);
	USB_TRANSFER SetInterface(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD, UCHAR, UCHAR);
	USB_TRANSFER GetDescriptor(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD, UCHAR, UCHAR, WORD, WORD, LPVOID);
	USB_TRANSFER SetDescriptor(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD, UCHAR, UCHAR, WORD, WORD, PVOID);
	USB_TRANSFER SetFeature(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD, WORD, UCHAR);
	USB_TRANSFER ClearFeature(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD, WORD, UCHAR);
	USB_TRANSFER GetStatus(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD, UCHAR, LPWORD);
	USB_TRANSFER SyncFrame(LPTRANSFER_NOTIFY_ROUTINE, LPVOID, DWORD, UCHAR, LPWORD);

	// attribute of default pipe.
	USHORT GetMaxPacketSize() {
		return DefaultDeviceDesc.wMaxPacketSize;
	};
	UCHAR GetEndPointAttribute() {
		return (DefaultDeviceDesc.bmAttributes & USB_ENDPOINT_TYPE_MASK);
	};
	USB_HANDLE GetUsbHandle() const {
		return hUsb;
	};
// default pipe function
	BOOL ResetDefaultPipe();
	BOOL IsDefaultPipeHalted(LPBOOL lpHalted);
	BOOL SetSyncFramNumber() {
		return GetFrameNumber(&m_dwSyncFrameNumber);
	};
	DWORD GetSyncFramNumber() {
		return m_dwSyncFrameNumber;
	};
	USHORT GetEP0PacketSize();

      private:
	const USB_HANDLE hUsb;
	USB_ENDPOINT_DESCRIPTOR DefaultDeviceDesc;
	DWORD m_dwSyncFrameNumber;


};

class UsbPipeService {
      public:
	UsbPipeService(LPCUSB_FUNCS ptrUsbFuncs, USB_HANDLE usbHandle, LPCUSB_ENDPOINT_DESCRIPTOR lpEndPointDescriptor, BOOL Async = FALSE);
	~UsbPipeService();
//pipe handling
//typedef BOOL (* LPABORT_PIPE_TRANSFERS)(USB_PIPE, DWORD);
	BOOL AbortPipeTransfers(DWORD dwFlags);
//typedef BOOL (* LPRESET_PIPE)(USB_PIPE);
	BOOL ResetPipe();
//typedef BOOL (* LPIS_PIPE_HALTED)(USB_PIPE, LPBOOL);
	BOOL IsPipeHalted(LPBOOL lpbHalted);

// It used by USBD

//Transfer commands
//typedef USB_TRANSFER (* LPISSUE_CONTROL_TRANSFER)(USB_PIPE,
//                                                  LPTRANSFER_NOTIFY_ROUTINE,
//                                                  LPVOID, DWORD, LPCVOID, DWORD,
//                                                  LPVOID, ULONG);
	virtual USB_TRANSFER IssueControlTransfer(UsbTransfer * uTransfer, LPCVOID lpvControlHeader, DWORD dwBufferSize, LPVOID lpvBuffer, ULONG uBufferPhysicalAddress);
//typedef USB_TRANSFER (* LPISSUE_BULK_TRANSFER)(USB_PIPE,
//                                               LPTRANSFER_NOTIFY_ROUTINE,
//                                               LPVOID, DWORD, DWORD, LPVOID,
//                                               ULONG);
	virtual USB_TRANSFER IssueBulkTransfer(UsbTransfer * uTransfer, DWORD dwBufferSize, LPVOID lpvBuffer, ULONG uBufferPhysicalAddress);

//typedef USB_TRANSFER (* LPISSUE_INTERRUPT_TRANSFER)(USB_PIPE,
//                                                    LPTRANSFER_NOTIFY_ROUTINE,
//                                                    LPVOID, DWORD, DWORD,
//                                                    LPVOID, ULONG);
	virtual USB_TRANSFER IssueInterruptTransfer(UsbTransfer * uTransfer, DWORD dwBufferSize, LPVOID lpvBuffer, ULONG uBufferPhysicalAddress);

//typedef USB_TRANSFER (* LPISSUE_ISOCH_TRANSFER)(USB_PIPE,
//                                                LPTRANSFER_NOTIFY_ROUTINE,
//                                                LPVOID, DWORD, DWORD, DWORD,
//                                                LPCDWORD, LPVOID, ULONG);
	virtual USB_TRANSFER IssueIsochTransfer(UsbTransfer * uTransfer, DWORD dwStartingFrame, DWORD dwFrames, LPCDWORD lpdwLengths, LPVOID lpvBuffer, ULONG uBufferPhysicalAddress);

//
	virtual DWORD ActionCompleteNotify(UsbTransfer * pTransfer);

      public:
	 DWORD GetPipeLastError() {
		return errorCode;
	};
	USB_PIPE GetPipeHandle() {
		return hPipe;
	};
	UCHAR GetEndPointAttribute() {
		return (DeviceDesc.bmAttributes & USB_ENDPOINT_TYPE_MASK);
	};
	USHORT GetMaxPacketSize() {
		return DeviceDesc.wMaxPacketSize;
	};
	BOOL isInPipe();
	BOOL isOutPipe();
	DWORD GetFlags() {
		return dwFlags;
	};
	DWORD SetFlags(DWORD newFlags) {
		return (dwFlags = newFlags);
	};
	DWORD SetErrorCode(DWORD aError) {
		return errorCode = aError;
	};
	LPCUSB_FUNCS GetUsbFuncPtr() const {
		return lpUsbFuncs;
	};
	LPUSB_ENDPOINT_DESCRIPTOR GetPipeDescriptorPtr() {
		return &DeviceDesc;
	};
	BOOL FormatData(LPBYTE pDataBuffer, DWORD dwDataLen);
	BOOL CheckData(LPBYTE pDataBuffer, DWORD dwDataLen, LPCHECK_RESULT pResult);
	CMutex pipeMutex;
      private:
	static DWORD WINAPI TransferNotify(LPVOID lpvNotifyParameter);
	USB_PIPE hPipe;
	DWORD dwFlags;
	LPCUSB_FUNCS lpUsbFuncs;
	DWORD errorCode;
	USB_ENDPOINT_DESCRIPTOR DeviceDesc;
	LPTRANSFER_NOTIFY_ROUTINE lpStartAddress;

#define ERROR_USB_PIPE_OPEN 0x100
#define ERROR_USB_NULL_FUNC 0x101
#define ERROR_USB_PIPE_CLOSE 0x102
#define ERROR_USB_PIPE_TRANSFER 0x103
#define ERROR_USB_PIPE_NO_MEMORY 0x104
#define ERROR_USB_PIPE_TIMEOUT  0x105
#define ERROR_USB_TRANSFER_STATUS 0x106
#define ERROR_USB_PIPE			0x200
};

#define MAX_PIPE 0x10
class UsbClientDrv:public UsbClass, public CMutex {
      public:
	UsbClientDrv(USB_HANDLE usbHandle, LPCUSB_FUNCS UsbFuncsPtr, LPCUSB_INTERFACE lpInterface, LPCWSTR szUniqueDriverId, LPCUSB_DRIVER_SETTINGS lpDriverSettings);
	virtual ~ UsbClientDrv();
	virtual BOOL Initialization() {
		return TRUE;
	};
	LPCUSB_ENDPOINT GetDescriptorPoint(DWORD dwIndex);
	DWORD GetNumOfEndPoints() {
		return dwNumEndPoints;
	};

	//Class Service
      private:
	DWORD dwNumEndPoints;
	LPUSB_ENDPOINT lpEndPoints;
	HANDLE hDevice;
};

#endif
