2007年3月20日 星期二

stream driver

建立stream driver需注意之事項,以527 為例
1.在project下建立自己的driver folder,ex: ARIEL
並修改dirs檔案,加入自己driver的名字
!if 0
Copyright (c) Microsoft Corporation. All rights reserved.
!endif
!...
DIRS=\
drvlib \
KEYBD \
up \
wolfson \
# @CESYSGEN IF CE_MODULES_BATTDRVR
battdrvr \
# @CESYSGEN ENDIF CE_MODULES_BATTDRVR
# @CESYSGEN IF CE_MODULES_WAVEAPI
wavedev \
# @CESYSGEN ENDIF CE_MODULES_WAVEAPI
# @CESYSGEN IF CE_MODULES_POINTER
...
# @CESYSGEN ENDIF CE_MODULES_NLEDDRVR
# @CESYSGEN ENDIF CE_MODULES_DEVICE
nvscdrv \
Display \
sdmmc \
Backlight \
otgdrv \
gsmdrvr \
sc16c652 \
tffs632 \
SerialCSR \
BARCODE \
ARIEL \



接著在driver folder內需建立.c、.def、source和makefile
,ex:ariel.c、ariel.def
(.def、source需修改,可以複製其他driver的來做,makefile亦可複製其他driver來用
)



2.修改source檔
!if 0
File: sources

Copyright (c) 2003 BSQUARE Corporation. All rights reserved.
!endif

RELEASETYPE=PLATFORM
TARGETNAME=ARIEL
TARGETTYPE=DYNLINK
DLLENTRY=DllEntry

TARGETLIBS= \
$(_COMMONSDKROOT)\lib\$(_CPUINDPATH)\coredll.lib \
$(_COMMONOAKROOT)\lib\$(_CPUINDPATH)\ceddk.lib \


DEFFILE= ariel.def
SOURCES= ariel.c



3.修改.def檔
;
; Copyright (c) Microsoft Corporation. All rights reserved.
;
;
; Use of this source code is subject to the terms of the Microsoft end-user
; license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
; If you did not accept the terms of the EULA, you are not authorized to use
; this source code. For a copy of the EULA, please see the LICENSE.RTF on your
; install media.
;
LIBRARY ARIEL

EXPORTS //基本export的function
ARI_Init
ARI_Deinit
ARI_Open
ARI_Close
ARI_Read
ARI_Write
ARI_Seek
ARI_IOControl
ARI_PowerUp
ARI_PowerDown



//ariel.c

#include
#include
#include "ariel.h"

//-------------------------------------------------------------------------
//
//DLL initialization entry point
//
BOOL
DllEntry(
HINSTANCE hinstDll, /*@parm Instance pointer. */
DWORD dwReason, /*@parm Reason routine is called. */
LPVOID lpReserved /*@parm system parameter. */
)
{
if (dwReason == DLL_PROCESS_ATTACH)
{
DEBUGREGISTER(hinstDll);
}

if (dwReason == DLL_PROCESS_DETACH)
{
}
//RETAILMSG( 1, (TEXT("DllEntry:Ariel:enter\r\n")));
return TRUE;
}
//===========================================================================

//---------------------------------------------------------------------------
//
//Driver initialization function
//
PHW_INDEP_INFO
ARI_Init(
PVOID pContext
)
{
PHW_INDEP_INFO pARIInfo;
RETAILMSG( 1, (TEXT("******ARI_Init:Ariel:enter******\r\n")));

//Allocate a drive instance structure
pARIInfo = (PHW_INDEP_INFO)LocalAlloc( LPTR, sizeof(HW_INDEP_INFO) );
if (!pARIInfo)
{
return NULL;
}
return (pARIInfo);
}
//=============================================================================

//-----------------------------------------------------------------------------
//
//Driver de-initialization function
//
BOOL ARI_Deinit(
DWORD hDeviceContext
)
{
RETAILMSG( 1, (TEXT("ARI_Deinit:Ariel:enter\r\n")));
return TRUE;
}

//=============================================================================

//-----------------------------------------------------------------------------
//
//Called when driver opened
//
DWORD ARI_Open(
DWORD hDeviceContext,
DWORD AccessCode,
DWORD ShareMode
)
{
RETAILMSG( 1, (TEXT("ARI_Open:Ariel:enter\r\n")));
return TRUE;
}
//==============================================================================

//------------------------------------------------------------------------------
//
//Called when driver closed
//
BOOL ARI_Close(
DWORD hOpenContext
)
{
RETAILMSG( 1, (TEXT("ARI_Close:Ariel:enter\r\n")));
return TRUE;
}
//==============================================================================

//------------------------------------------------------------------------------
//
//Called when driver read
//
DWORD ARI_Read(
DWORD hOpenContext,
LPVOID pBuffer,
DWORD Count
)
{
RETAILMSG( 1, (TEXT("ARI_Read:Ariel:enter\r\n")));
return Count;
}
//==============================================================================

//------------------------------------------------------------------------------
//
//Called when driver written
//
DWORD ARI_Write(
DWORD hOpenContext,
LPVOID pBuffer,
DWORD Count
)
{
RETAILMSG( 1, (TEXT("ARI_Write:Ariel:enter\r\n")));
return Count;
}
//==============================================================================

//------------------------------------------------------------------------------
//
//Called when SeetFilePtr called
//
DWORD ARI_Seek(
DWORD hOpenContext,
long Amount,
WORD Type
)
{
RETAILMSG( 1, (TEXT("ARI_Seek:Ariel:enter\r\n")));
return 0;
}
//==============================================================================

//------------------------------------------------------------------------------
//
//Called when DeviceIOControl called
//
BOOL ARI_IOControl(
PHW_INDEP_INFO pOTGInfo,
DWORD dwCode,
PBYTE pBufIn,
DWORD dwLenIn,
PBYTE pBufOut,
DWORD dwLenOut,
PDWORD pdwActualOut
)
{

RETAILMSG( 1, (TEXT("ARI_IOControl:Ariel:enter dwCode=%d dwLenIn=%d dwLenOut=%d\r\n"),dwCode,dwLenIn,dwLenOut));
{
int i=0;

RETAILMSG( 1, (TEXT("pBufIn= \r\n")));
for(i=0;iARI_PowerDown(
DWORD hDeviceContext
)

{
RETAILMSG( 1, (TEXT("ARI_PowerDown:Ariel:enter\r\n")));
}
//==============================================================================

//------------------------------------------------------------------------------
//
//Called when resumes
//
void ARI_PowerUp(
DWORD hDeviceContext
)

{
RETAILMSG( 1, (TEXT("ARI_PowerUp:Ariel:enter\r\n")));
}
//==============================================================================

4.修改platform.bib檔
加入
ariel.dll $(_FLATRELEASEDIR)\ariel.dll NK SH



5.修改platform.reg
加入
[HKEY_LOCAL_MACHINE\Drivers\BuiltIn\ARI]
"Prefix"="ARI"
"Dll"="ariel.dll"
"Order"=dword:0
"Index"=dword:0



ps.因為只有在 platform\...\files 下有修改,如果platform builder沒有build過的話,就需手動複製貼在 PBWorkspaces\...\RelDir\...Release中的platform.reg內

2007年3月13日 星期二

UCB1400_Tanjay

***ac97 需注意的三種Reset
1.Cold Reset:ac97 Controller Registers的值會被初始成power on reset的default值。Reset為Low,BIT_CLK會立即不見,Reset為High,SYNC和BIT_CLK會約隔355毫秒不見。
2.Register Reset:寫任何值在Codec register(0x00h)都會做Reset,當Reset完後只有Codec Register的值變回default值。BIT_CLK和SYNC都不會改變。
3.Warm Reset:會重新觸發AC-Link但不影響Codec Register的值,做法就是直接設定Codec Register(0x26h)。BIT_CLK會為Low,SYNC會High一段時間後為Low。

***對ucb1400 codec做錄放音功能。
1.先對GPIO做設定。
void ucb1400_gpio_cfg()
{
GPIO_set_dir(28,INPUT); //BitClk
GPIO_set_dir(29,INPUT); //DtatIn
GPIO_set_dir(30,OUTPUT); //DataOut
GPIO_set_dir(31,OUTPUT); //SYNC
GPIO_set_dir(113,OUTPUT); //Reset
GPIO_set_alternate(28,1);
GPIO_set_alternate(29,1);
GPIO_set_alternate(30,2);
GPIO_set_alternate(31,2);
GPIO_set_alternate(113,0);
GPIO_set_output_bit(113);
GPIO_set_dir(10,OUTPUT); //speaker enable
GPIO_set_output_bit(10);
}

2.錄音,對Codec Register做設定。
void AudioRecord(unsigned* buffer,unsigned bufferSize)
{

writecodecreg(0x2,0x0000);
readcodecreg(0x2);//read it for check
writecodecreg(0xe,0x0040);
readcodecreg(0xe);
writecodecreg(0x1a,0x0000);
readcodecreg(0x1a);
sleep(1); // have to wait a moment
writecodecreg(0x1c,0x0f0f);
readcodecreg(0x1c);

if((pac97_regs->mcsr & 0x10))
{
pac97_regs->mcsr = 0x10;
}

if((pac97_regs->pisr & 0x10))
{
pac97_regs->pisr = 0x10;
}


while(bufferSize-- > 0)
{

/*
* Wait for the start of a new frame.
* This is signified by a pulse on the SYNC line.
*/
while ((GPIO_get_level(BSP_GPIO_AC97_SYNC)!= 0));
/* Wait for it to go high */
while ((GPIO_get_level(BSP_GPIO_AC97_SYNC)!= 1));
/* Wait for it to go low */

*buffer++ = pac97_regs->pcdr;

}
}

3.放音,對Codec Register做設定。
void AudioPlay(unsigned* buffer, unsigned bufferSize)
{
writecodecreg(0x6a,0x0349);
readcodecreg(0x6a);
writecodecreg(0x2a,0x0000);
readcodecreg(0x2a);
writecodecreg(0x2c,0xbb80);
readcodecreg(0x2c);
sleep(1);
writecodecreg(0x2,0x1010);
readcodecreg(0x2);

while(bufferSize-- >0)
{

while((pac97_regs->posr & 0x10))
{
pac97_regs->posr = 0x10;
}

while ((GPIO_get_level(BSP_GPIO_AC97_SYNC)!= 0));
/* Wait for it to go high */
while ((GPIO_get_level(BSP_GPIO_AC97_SYNC)!= 1));
/* Wait for it to go low */
pac97_regs->pcdr =*buffer++;

}
}

2007年3月8日 星期四

BattDrv_661

1. 有可能會因為wm9712忙碌的關係導致抓取不到電壓值。
抓取6次wm9712電壓取平均,若其中有n次miss則取n次平均。
//BspBattPdd.c
static USHORT
SYSCheckBattVoltage(BOOL bSet)
{

...
for(iCount=0;iCount<6;icount++)
{
if (usWm9712ADD == 0)
usMiss++;
else
{
usVolTmp[iCount] = usWm9712ADD;
usTemp+=usWm9712ADD;
}
Sleep(10);
}

if(ADC_COUNT>usMiss)
usWm9712ADD=usTemp/(ADC_COUNT-usMiss); //internal voltage
else
usWm9712ADD=usTemp;
avgVol = ((usWm9712ADD*806)/1000)*3;
....
}

2.ADC output levels are calculated by [internal voltage/805.86uV]



3.每次resume重讀registry會影響resume的時間,hold住一段時間會造成device開啟不了,因此將 registry移到BatteryPDDInitialize讀取。
//battif.c
BOOL WINAPI
BatteryPDDInitialize(LPCTSTR pszRegistryContext)
{

BspGetSettingFromRegistry(BAT_REG_LEVEL1, &g_BatRegValue[0]);
BspGetSettingFromRegistry(BAT_REG_LEVEL2, &g_BatRegValue[1]);
BspGetSettingFromRegistry(BAT_REG_LEVEL3, &g_BatRegValue[2]);
BspGetSettingFromRegistry(BAT_REG_LEVEL4, &g_BatRegValue[3]);
BspGetSettingFromRegistry(BAT_REG_LEVEL5, &g_BatRegValue[4]);
BspGetSettingFromRegistry(BAT_REG_LEVEL6, &g_BatRegValue[5]);
BspGetSettingFromRegistry(BAT_REG_LEVEL7, &g_BatRegValue[6]);
BspGetSettingFromRegistry(BAT_REG_LEVEL8, &g_BatRegValue[7]);
BspGetSettingFromRegistry(BAT_REG_LEVEL9, &g_BatRegValue[8]);
BspGetSettingFromRegistry(BAT_REG_LEVEL10, &g_BatRegValue[9]);

BspGetSettingFromRegistry(BAT_REG_LEVEL0, &g_BatChargingRegValue);

}

4.因為計算出來的
avgVol會有些上下跳動的情形而導致show出來的percentage也有變化,所以加了一些修改,感覺有點小作弊。
//BspBattPdd.c
static USHORT
SYSCheckBattVoltage(BOOL bSet)
{
...

if(bSet)

{

if(iMax

{

iMax=avgVol;

iMin=5000;

}

usBatChargingPer= (USHORT)BattChargingGetLevel(iMax);

return usBatChargingPer;

}

if(iMin>avgVol)

{

iMin=avgVol;

iMax=0;

}


usBatteryPer = (USHORT)BattGetLevel(iMin);

return (usBatteryPer);

}

4.因為registry定義,加上判斷suspend時間點的關系,導致低電量時device自行進入suspend後做charging再按resume會有bug產生,device會show出剩餘10%電量後再show出charging,照道理是一按resume後會show charging才是。
以下對code再加判斷解決。

//BspBattPdd.c
DWORD BattGetLevel(DWORD dwVoltage)
{
...
if(g_icount<5) g_icount="0;" g_icount="0;" style="color: rgb(255, 0, 0);">if(BspGetBatteryFlag()==PDD_BATTERY_CHARGING)

{
return BATTERY_PERCENTAGE_UNKNOWN;
}
else
{
return 10;
}
}
...
}

//battif.c
BatteryPDDGetStatus(
PSYSTEM_POWER_STATUS_EX2 pstatus, PBOOL pfBatteriesChangedSinceLastCall)
{
...
if (PDD_BATTERY_CHARGING == battery_status )
{
RETAILMSG(ZONE_REG_PRINT, (TEXT("+Battery status PDD_BATTERY_CHARGING... \r\n")));

ucBatChargingPer=BspFuelGaugeResetBatStatusInPercent();
BspNotifyLed(FALSE);
if(ucBatChargingPer==100)
{
sps.BatteryFlag = BATTERY_FLAG_HIGH;
sps.BatteryLifePercent = 100;
BspNotifyLed(FALSE);
IOW_REG_OR(ULONG, &(v_pGpioRegs->gpio[5].paden), GPIO23);
PIO_OUTPUT_ZERO (GPIO, GPIO_GROUP(5), GPIO_INDEX(23));
PIO_OUTPUT_ENABLE ( GPIO, GPIO_GROUP (5), GPIO_INDEX (23) );
}else
{
sps.BatteryFlag = BATTERY_FLAG_CHARGING;
sps.BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
BspNotifyLed(FALSE);
IOW_REG_OR(ULONG, &(v_pGpioRegs->gpio[5].paden), GPIO23);
PIO_OUTPUT_ONE (GPIO, GPIO_GROUP(5), GPIO_INDEX(23));
PIO_OUTPUT_ENABLE ( GPIO, GPIO_GROUP (5), GPIO_INDEX (23) );
}
}
else
{
ucBatteryPer = BspFuelGaugeGetBatStatusInPercent();

if(ucBatteryPer == dwTenPercentage)
SetEvent(hBattLowEvent);
if(ucBatteryPer==BATTERY_PERCENTAGE_UNKNOWN)
{
sps.BatteryFlag = BATTERY_FLAG_CHARGING;
sps.BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
}
else if(ucBatteryPer >= dwHighBattPercentage)
{
sps.BatteryFlag = BATTERY_FLAG_HIGH;
BspNotifyLed(FALSE);
sps.BatteryLifePercent = ucBatteryPer;
}
else if (( ucBatteryPer =dwLowBattPercentage))
{
sps.BatteryFlag = BATTERY_FLAG_LOW;
BspNotifyLed(TRUE);
sps.BatteryLifePercent = ucBatteryPer;
}
else if(ucBatteryPer<=dwLowBattPercentage)
{
sps.BatteryFlag = BATTERY_FLAG_CRITICAL;
BspNotifyLed(TRUE);
sps.BatteryLifePercent = ucBatteryPer;
}

}
...
}