2009年9月18日 星期五

[WIA]Item Tree





***************************************************************************

1. Item Tree 架構, 如圖1
1.1 有一個Root item 及一個 Flatbed or Feeder item(Flatbed 和 Feeder 共用一個Item)
1.2 每一個item 中有許多WINDOWS 定義好的property (DIP_xxx_xxx, DPA_xxx_xxx, ...)
1.3 0000\xxx 或 0001\xxx 為 WINDOWS 決定的。


2. 可以使用wiatest.exe 看到Item Tree 中的每個Item 及其所有的property, 如圖2
3. Item Tree 由AP, Wia service , mini driver 各擁有一份。wia service 會自行同步這三份。



圖1:



圖2:







建立時機點:


//
//建立Item 的架構
//
IWiaMiniDrv::drvInitializeWia(...)
{
.
.
//建立Root Item
IWiaDrvItem *pIWiaDrvRootItem = NULL;
wiasCreateDrvItem(... , &pIWiaDrvRootItem)
.
.
//建立Flatbed Item
IWiaDrvItem *pIWiaDrvNewItem = NULL;
wiasCreateDrvItem(... , &pIWiaDrvNewItem)

//attach Flatbed Item to Root Item
pIWiaDrvNewItem->AddItemToFolder(pIWiaDrvRootItem);
.
.
.

}


//
//建立每個Item 中的property 及其初始值, 一個Item 會進來一次(Root 一次, Flatbed 一次)
//
IWiaMiniDrv::drvInitItemProperties(...)
{
//判斷進來的是Root 或 Flatbed 寫入相對映的property(使用wiasXXX 的function)
//ex:
//wiasSetItemPropNames();
//wiasWriteMultiple();
//wiasSetItemPropAttribs();
//.
//.
.
.
.
}




p.s.
在Vista/7 下,其Item Tree架構差不多,如下:

1. Item Tree 架構,
1.1 有一個Root item 及一個 Flatbed or Feeder item or 其它的 Item(Flatbed 和 Feeder 各自有其Item)
1.2 每一個item 中有許多WINDOWS 定義好的property (DIP_xxx_xxx, DPA_xxx_xxx, ...), 但有些property 的名稱改變,如

(DPA_xxx_xx -> DPS_xxx_xxx), 而且可能會有所移動(ex: 從 Root -> Flatbed)

2. 可以使用wiainfo2.exe 看到Item Tree 中的每個Item 及其所有的property
3. Item Tree 由AP, Wia service , mini driver 各擁有一份。wia service 會自行同步這三份。

2009年9月10日 星期四

[WIA] the order of Release

CWiaDevice::CWiaDevice

HRESULT CWIADriver::drvInitializeWia(__inout BYTE *pWiasContext,
LONG lFlags,
__in BSTR bstrDeviceID,
__in BSTR bstrRootFullItemName,
__in IUnknown *pStiDevice,
__in IUnknown *pIUnknownOuter,
__out IWiaDrvItem **ppIDrvItemRoot,
__out IUnknown **ppIUnknownInner,
__out LONG *plDevErrVal)





HRESULT CWIADriver::drvUnInitializeWia(__inout BYTE *pWiasContext)

CWiaDevice::~CWiaDevice


//
Wia UI 出現時一定會呼叫drvInitializeWia,
但drvInitializeWia 和 drvUnInitializeWia 並不一定會成對出現。所以有可能呼叫多次的drvInitializeWia, 而只呼叫一次的drvUnInitializeWia.

drvInitializeWia: 只在第一次呼叫時初始化所需資源。之後只要回傳ok.
drvUnInitializeWia:
CWiaDevice::~CWiaDevice:
1. 釋放資源
2. CancelIO(SetNotificationHandle(NULL))
3. Release handle(CreateFile 建立用來控制device)





定義:
******************************************************************************
一個 Hanlde週期(Handle life cycle):
1. device 插入到拔出
2. 開機到關機


WIA UI:
default WIA AP(offered by WINDOWS)


class CWIADriver : public INonDelegatingUnknown, // NonDelegatingUnknown
public IStiUSD, // STI USD interface
public IWiaMiniDrv // WIA Minidriver interface
CWIADriver :
component 內的一個 class 用來提供 IStiUSD, IWiaMiniDrv兩個 Interface


說明:
******************************************************************************
IStiUSD::Initialize():
週期時機:週期開始
呼叫時機:一偵測到Device 的存在--安裝完Driver或插入Device(device 插入或開機)
應作動作:初始化 Handle(created by CreateFile)

IWiaMiniDrv::drvInitializeWia:
週期時機:週期內
呼叫時機:建立連線(IWiaDevMgr::CreateDevice), ex: 打開WIA UI
應作動作:
1. 在第一次進來,保存傳入的IStiDevice 指標(IStiDevice 為 IStiUSD的使用者介面),
下次再進來時便以此指標是否已有值來判斷是否為一個週期的開始,
指標內有值便為週期內,否則為一新的週期。
2. 增加連線計數(進來一次加一)

IWiaMiniDrv::drvUnInitializeWia:
週期時機:週期內
呼叫時機:結束連線
應作動作:
1. 減少連線計數(進來一次減一)
如果連線計數為0 時釋放掉一些週期內可以釋放的large memory


CWiaDevice::~CWiaDevice:
週期時機:週期結束
呼叫時機:一偵測到Device 的'不'存在(device 拔出或關機)
應作動作:
1. 釋放 Handle(created by CreateFile),
如果有支援push mode 得先CancelIO(by SetNotificationHandle(NULL))


WDK 中說明:
1. 並不保證每一次的IWiaMiniDrv::drvInitializeWia 和 IWiaMiniDrv::drvUnInitializeWia 會成對出現。
2. 週期內,不保證每一次(除了第一次)都會先呼叫IWiaMiniDrv::drvInitializeWia
再呼叫其它 IWiaMiniDrv的function.

2009年8月31日 星期一

指標的指標使用的兩種時機

1. function
真正的記憶體在function 內被allocate, caller 只要有一個指標,傳入指標的位址(即指標的指標)即可使用。
只是使用完畢得由caller release 記憶體。

#define MEM_SIZE 100


//function code:
Func(BYTE **pMem)
{
*pMem= malloc(100);
}

//caller code:
Main()
{
BYTE *pBuf=NULL;


Func(&pBuf);

//
//do something with "pBuf"
//
.
.
.

//
//Release mem
//
Free(pBuf);
}


2. 指標的陣列:
等同是create 一個指標的陣列
Method1: by Array
Method2: by pointer


#define METHOD_ARRAY


Main()
{
int **pArray=NULL;
int pIntArray[3];
int i;

pArray = (int **)malloc(3*sizeof(int*));

//assign address
for (i=0; i<3; i++)
{
#ifdef METHOD_ARRAY
//
// by Array
//
pArray[i] = &(pIntArray[i]);
#else
//
// by pointer
//
*(pArray+i)= &(pIntArray[i]);
#endif

}

//show
for (i=0; i<3; i++)
{
#ifdef METHOD_ARRAY
//
// by Array
//
printf("%d\n", *(ppValue[i]));
#else
//
// by pointer
//
printf("%d\n", *((int *)*(ppValue+i)));
#endif
}

free(pArray);

}

2009年7月22日 星期三

Push Mode簡介



說明:
"push mode" 是指device 上觸發了某些事件,這些事件有必要讓PC 端知道。
如在Scanner 上按下了掃描鍵。PC 端應立刻讀取scanner 上的掃描資訊,進行掃描。

基本上分為兩種:
1. polling: 每隔一段時間便向device 詢問相關資訊。
2.1 function 呼叫時機:
自行參考xp ddk下的demo

2. asynchronous: device 透過 interrupt 發送相關資訊上來。
2.1 function 呼叫時機:
//initialization
IStiUSD::Initialize()
IStiUSD::GetCapabilities()
IStiUSD::GetStatus()
IStiUSD::SetNotificationHandle()

//when device send a interrupt
IStiUSD::GetNotificationData()

//Set again
IStiUSD::SetNotificationHandle()

.
.
.

Function 簡介(asynchronous):

IStiUSD::Initialize()
a. 用Createfile()取得另一個Handle,有別於read/write 用的那一個。

IStiUSD::GetCapabilities()
a. 提供支援STI 的版本(xp: STI_VERSION, vista/7: STI_VERSION_3)
b. 告知是否支援wia, 支援何種 push mode(polling/ asynchronous)

IStiUSD::GetStatus()
a. 由mask 中的
STI_DEVSTATUS_ONLINE_STATE 決定是否告知device online,
STI_DEVSTATUS_EVENTS_STATE 決定是否告知有無event pending-----只有 polling mode此flag 才會被設立
b. 告知是否Device online

IStiUSD::SetNotificationHandle()
a. 用來DeviceIoControl(,IOCTL_WAIT_ON_DEVICE_EVENT,..)來幫助WIA Service 等待device 的interrupt.
b. 支援 asynchronous才會進來此function,支援 polling 則不會。

IStiUSD::GetNotificationData()
a. WIA Service 一旦等待到Device interrupt 便會呼叫此function
b. 在此從device 取得相關資訊,並由此資訊判斷屬於哪個Event ,再回傳此Event給 WIA Service

IWiaMiniDrv::drvGetCapabilities()
a. 告知支援的Event 及command

IWiaMiniDrv::drvNotifyPnpEvent
a. 當asynchronous 模式且pnp Event 為WIA_EVENT_POWER_RESUME ,得再次呼叫IStiUSD::SetNotificationHandle() 來設立WIA Service的等待模式。




INF File

"Capabilities" in INF DDInstall section:

bit 0(STI_GENCAP_NOTIFICATIONS): 支援push mode 預設模式 為 asynchronous
bit 1(STI_GENCAP_POLLING_NEEDED): 改變模式為 polling
bit 2(STI_GENCAP_GENERATE_ARRIVALEVENT):
bit 3(STI_GENCAP_AUTO_PORTSELECT):
bit 4(STI_GENCAP_WIA): 支援WIA
bit 5(STI_GENCAP_SUBSET):


ex:
.
.
.
[Manufacturer]
%Mfg%=Models

[Models]
%WIASample.DeviceDesc% = WIASample.Scanner, MICROSOFT_WIASCANR_TESTDEVICE_PNP_ID

[WIASample.Scanner]
Capabilities=0x31(支援wia(ddk 中demo code 中把STI_GENCAP_SUBSET 設起來), 且push mode 的模式為 asynchronous)
.
.
.


2009年7月18日 星期六

WIA 流程簡介




流程說明:
Tip:refer to win DDK(xp) "Calling Order for Minidriver Functions"


1. 初始化:

STI---

IStiUSD::Initialize()
a. 用Createfile()取得Handle
b. 打開 驅動程式鍵(driver key)下的"DeviceData" key,可在此存放一些自訂的資訊。

IStiUSD::GetCapabilities()
a. 提供支援STI 的版本(xp: STI_VERSION, vista/7: STI_VERSION_3)
b. 告知是否支援wia, 支援何種 push mode(polling/ asynchronous)

IStiUSD::GetStatus()
a. 告知是否Device online
b. 有沒有Event pending 中


WIA---

IWiaMiniDrv::drvInitializeWia()
a. 保存 指向IStiDevice 的 pointer(間接呼叫IStiUSD)
b. 建立 Item Tree 中的 所有 Item ( xp: 0000\Root 和 0000\Root\Flatbed or 0000\Root\Feeder 這2個Item, vista/7: 0000\Root 和 0000\Root\Flatbed, 0000\Root\Flatbed, ..等至少2個以上的Item)


IWiaMiniDrv::drvGetCapabilities()
a. 告知支援的Event 及command

IWiaMiniDrv::drvInitItemProperties()
a. 建立Item Tree 中每一個Item 中所需的property
b. 如果Item Tree 中有2 個Item , 此function 會被呼叫 2次(呼叫次數為Item Tree 中 Item的個數) IWiaMiniDrv::drvValidateItemProperties()




2. (property validation) UI 改變掃描參數或硬體資訊

WIA---

IWiaMiniDrv::drvValidateItemProperties()

a. WIA AP 改變了 Item Tree 中 Item 裡的property所含的數值便會觸發此fucntion (如圖中 相片類型由 彩色相片->灰階圖片。)



3. 建立傳輸

STI---

IStiUSD::LockDevice()
IStiUSD::RawReadCommand()
IStiUSD::RawWriteCommand()
IStiUSD::RawReadData()
IStiUSD::RawWriteData()
IStiUSD::UnLockDevice()


WIA---

IWiaMiniDrv::drvLockWiaDevice()
IWiaMiniDrv::drvWriteItemProperties()
IWiaMiniDrv::drvAcquireItemData()
IWiaMiniDrv::drvUnLockWiaDevice()


3.1. Lock/UnLock:
依接口,效能考量而有不同。(因為STI 支援多個instance 同時呼叫一個Device所以在每次read/write時要做lock的動作)

STI---
read command-> parse command -> read/write data
write command-> read/write data

其實只要有read/ write function 就行了。
反正command 也只是一塊buffer 而已 所以只要
read: read: IStiUSD::LockDevice() ->IStiUSD::RawReadData()->IStiUSD::UnLockDevice()
write: write: IStiUSD::LockDevice() ->IStiUSD::RawWriteData()->IStiUSD::UnLockDevice()

//以下的function可以不用implement
IStiUSD::RawReadCommand()--no use
IStiUSD::RawWriteCommand()--no use

WIA---
Lock/UnLock: 和STI 的考量點一樣。


3.2 Transfer:

xp/nt:
3.2.1 WIA 對device 的read/write 由呼叫 以上的STI read/write function 完成。
3.2.2 IWiaMiniDrv::drvWriteItemProperties(): 寫入欲掃描的影像資訊到device 上
IWiaMiniDrv::drvAcquireItemData() : 透過callback function 回傳影像資料到WIA Service

3.2.3 [IWiaMiniDrv::drvWriteItemProperties() + IWiaMiniDrv::drvAcquireItemData()] :
為回傳從Device 取得的一頁影像到WIA Service. 如有4 頁影像,便連續進入4次(flatbed, simplex 一張紙只能掃出1頁,duplex 能掃出2頁)


Vista/7:
3.2.1 WIA 對device 的read/write 由呼叫 以上的STI read/write function 完成。
3.2.2 IWiaMiniDrv::drvWriteItemProperties(): 沒有作用
IWiaMiniDrv::drvAcquireItemData() : 透過IStream 回傳影像資料到WIA Service

3.2.3 [IWiaMiniDrv::drvAcquireItemData()] :
在此function 內完成一個scan job, 一次掃描只進來一次,一次完成所有頁數的掃描。

2009年7月15日 星期三

WIA 架構簡介

















Component 介紹:

1. WIA AP: 使用 wia 的 application
2. WIA Service: windows 內的一個Service
3. WIA mini driver: 要implement 的對象(提供 IWiaMiniDrv, IStiUSD 兩個inteface)
4. sti.dll: STI (提供 IStiDevice 這個 interface)
5. WIA Driver service library: 提供一些輔助用的function (ex: wiasXXX,...), 用來存取 Item Tree
6. Driver(USB, SCSI,...): 依scanner 提供的接口而變,大多是USB.
7. Item Tree:
7.1. 將 Device 的硬體資訊存入 個別Item(ex: 0000\Root, 0000\Root\Flatbed,..) 的property 中.
7.2. 三份Item Tree 是一樣的。(一個 WIA AP 會有自己的一份)
7.3. 由WIA Service 來主導 WIA AP 和 WIA mini driver 的協調
8. CONTEXT: WIA Service 呼叫 WIA mini driver 的 IWiaMiniDrv 介面function 時所帶之參數


2009年7月13日 星期一

Big/Little Endian

-------------------------------------
定義:
-------------------------------------
MSB(Most Significant Bit/Byte)
LSB(Least Significant Bit/Byte)

以32 bits cpu 來看:

暫存器每個BYTE 的index 如下。








-------------------------------------
解釋:
-------------------------------------
Big/Little endian 的差別在於。是由MSB 開始copy 每一 BYTE 的值到記憶體中,或是由LSB開始。



-------------------------------------
例子:
-------------------------------------

//Big endian

















//Little endian