os/kernelhwsrv/kerneltest/e32test/dma/dmasim.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of the License "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 // e32test\dma\dmasim.cpp
    15 // DMA framework Platform Specific Layer (PSL) for software-emulated
    16 // DMA controller used for testing the DMA framework PIL.
    17 // 
    18 //
    19 
    20 #include <drivers/dma.h>
    21 #include <kernel/kern_priv.h>
    22 
    23 
    24 const char KDmaPanicCat[] = "DMASIM";
    25 
    26 const TInt KMaxTransferSize = 0x1FFF;
    27 const TInt KMemAlignMask = 3; // memory addresses passed to DMAC must be multiple of 4
    28 const TInt KBurstSize = 0x800;
    29 
    30 typedef void (*TPseudoIsr)();
    31 
    32 const TInt KChannelCount = 4;								// # of channels per controller
    33 const TInt KDesCount = 256;									// # of descriptors allocated per controller
    34 
    35 //////////////////////////////////////////////////////////////////////////////
    36 // SOFTWARE DMA CONTROLLER SIMULATION
    37 //////////////////////////////////////////////////////////////////////////////
    38 
    39 class DmacSb
    40 /** Single-buffer DMA controller software simulation */
    41 	{
    42 public:
    43 	enum { ECsRun = 0x80000000 };
    44 public:
    45 	static void DoTransfer();
    46 private:
    47 	static void BurstTransfer();
    48 private:
    49 	static TInt CurrentChannel;
    50 public:
    51 	// pseudo registers
    52 	static TUint8* SrcAddr[KChannelCount];
    53 	static TUint8* DestAddr[KChannelCount];
    54 	static TInt Count[KChannelCount];
    55 	static TUint32 ControlStatus[KChannelCount];
    56 	static TUint32 CompletionInt;
    57 	static TUint32 ErrorInt;
    58 	// hook for pseudo ISR
    59 	static TPseudoIsr Isr;
    60 	// transfer failure simulation
    61 	static TInt FailCount[KChannelCount];
    62 	};
    63 
    64 TUint8* DmacSb::SrcAddr[KChannelCount];
    65 TUint8* DmacSb::DestAddr[KChannelCount];
    66 TInt DmacSb::Count[KChannelCount];
    67 TUint32 DmacSb::ControlStatus[KChannelCount];
    68 TUint32 DmacSb::CompletionInt;
    69 TUint32 DmacSb::ErrorInt;
    70 TPseudoIsr DmacSb::Isr;
    71 TInt DmacSb::FailCount[KChannelCount];
    72 TInt DmacSb::CurrentChannel;
    73 
    74 void DmacSb::DoTransfer()
    75 	{
    76 	if (ControlStatus[CurrentChannel] & ECsRun)
    77 		{
    78 		if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0)
    79 			{
    80 			ControlStatus[CurrentChannel] &= ~ECsRun;
    81 			ErrorInt |= 1 << CurrentChannel;
    82 			Isr();
    83 			}
    84 		else
    85 			{
    86 			//__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::DoTransfer channel %d", CurrentChannel));
    87 			if (Count[CurrentChannel] == 0)
    88 				{
    89 				//__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::DoTransfer transfer complete"));
    90 				ControlStatus[CurrentChannel] &= ~ECsRun;
    91 				CompletionInt |= 1 << CurrentChannel;
    92 				Isr();
    93 				}
    94 			else
    95 				BurstTransfer();
    96 			}
    97 		}
    98 
    99 	CurrentChannel++;
   100 	if (CurrentChannel >= KChannelCount)
   101 		CurrentChannel = 0;
   102 	}
   103 
   104 void DmacSb::BurstTransfer()
   105 	{
   106 	//__KTRACE_OPT(KDMA, Kern::Printf("DmacSb::BurstTransfer"));
   107 	TInt s = Min(Count[CurrentChannel], KBurstSize);
   108 	memcpy(DestAddr[CurrentChannel], SrcAddr[CurrentChannel], s);
   109 	Count[CurrentChannel] -= s;
   110 	SrcAddr[CurrentChannel] += s;
   111 	DestAddr[CurrentChannel] += s;
   112 	}
   113 
   114 //////////////////////////////////////////////////////////////////////////////
   115 
   116 class DmacDb
   117 /** Double-buffer DMA controller software simulation */
   118 	{
   119 public:
   120 	enum { ECsRun = 0x80000000, ECsPrg = 0x40000000 };
   121 public:
   122 	static void Enable(TInt aIdx);
   123 	static void DoTransfer();
   124 private:
   125 	static TInt CurrentChannel;
   126 private:
   127 	// internal pseudo-registers
   128 	static TUint8* ActSrcAddr[KChannelCount];
   129 	static TUint8* ActDestAddr[KChannelCount];
   130 	static TInt ActCount[KChannelCount];
   131 public:
   132 	// externally accessible pseudo-registers
   133 	static TUint32 ControlStatus[KChannelCount];
   134 	static TUint8* PrgSrcAddr[KChannelCount];
   135 	static TUint8* PrgDestAddr[KChannelCount];
   136 	static TInt PrgCount[KChannelCount];
   137 	static TUint32 CompletionInt;
   138 	static TUint32 ErrorInt;
   139 	// hook for pseudo ISR
   140 	static TPseudoIsr Isr;
   141 	// transfer failure simulation
   142 	static TInt FailCount[KChannelCount];
   143 	static TInt InterruptsToMiss[KChannelCount];
   144 	};
   145 
   146 TUint8* DmacDb::PrgSrcAddr[KChannelCount];
   147 TUint8* DmacDb::PrgDestAddr[KChannelCount];
   148 TInt DmacDb::PrgCount[KChannelCount];
   149 TUint8* DmacDb::ActSrcAddr[KChannelCount];
   150 TUint8* DmacDb::ActDestAddr[KChannelCount];
   151 TInt DmacDb::ActCount[KChannelCount];
   152 TUint32 DmacDb::ControlStatus[KChannelCount];
   153 TUint32 DmacDb::CompletionInt;
   154 TUint32 DmacDb::ErrorInt;
   155 TPseudoIsr DmacDb::Isr;
   156 TInt DmacDb::FailCount[KChannelCount];
   157 TInt DmacDb::InterruptsToMiss[KChannelCount];
   158 TInt DmacDb::CurrentChannel;
   159 
   160 void DmacDb::Enable(TInt aIdx)
   161 	{
   162 	if (ControlStatus[aIdx] & ECsRun)
   163 		ControlStatus[aIdx] |= ECsPrg;
   164 	else
   165 		{
   166 		ActSrcAddr[aIdx] = PrgSrcAddr[aIdx];
   167 		ActDestAddr[aIdx] = PrgDestAddr[aIdx];
   168 		ActCount[aIdx] = PrgCount[aIdx];
   169 		ControlStatus[aIdx] |= ECsRun;
   170 		}
   171 	}
   172 
   173 void DmacDb::DoTransfer()
   174 	{
   175 	if (ControlStatus[CurrentChannel] & ECsRun)
   176 		{
   177 		if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0)
   178 			{
   179 			ControlStatus[CurrentChannel] &= ~ECsRun;
   180 			ErrorInt |= 1 << CurrentChannel;
   181 			Isr();
   182 			}
   183 		else
   184 			{
   185 			if (ActCount[CurrentChannel] == 0)
   186 				{
   187 				if (ControlStatus[CurrentChannel] & ECsPrg)
   188 					{
   189 					ActSrcAddr[CurrentChannel] = PrgSrcAddr[CurrentChannel];
   190 					ActDestAddr[CurrentChannel] = PrgDestAddr[CurrentChannel];
   191 					ActCount[CurrentChannel] = PrgCount[CurrentChannel];
   192 					ControlStatus[CurrentChannel] &= ~ECsPrg;
   193 					}
   194 				else
   195 					ControlStatus[CurrentChannel] &= ~ECsRun;
   196 				if (InterruptsToMiss[CurrentChannel] > 0)
   197 					InterruptsToMiss[CurrentChannel]--;
   198 				else
   199 					{
   200 					CompletionInt |= 1 << CurrentChannel;
   201 					Isr();
   202 					}
   203 				}
   204 			else
   205 				{
   206 				TInt s = Min(ActCount[CurrentChannel], KBurstSize);
   207 				memcpy(ActDestAddr[CurrentChannel], ActSrcAddr[CurrentChannel], s);
   208 				ActCount[CurrentChannel] -= s;
   209 				ActSrcAddr[CurrentChannel] += s;
   210 				ActDestAddr[CurrentChannel] += s;
   211 				}
   212 			}
   213 		}
   214 
   215 	CurrentChannel++;
   216 	if (CurrentChannel >= KChannelCount)
   217 		CurrentChannel = 0;
   218 	}
   219 
   220 
   221 //////////////////////////////////////////////////////////////////////////////
   222 
   223 class DmacSg
   224 /** Scatter/gather DMA controller software simulation */
   225 	{
   226 public:
   227 	enum { EChannelBitRun = 0x80000000 };
   228 	enum { EDesBitInt = 1 };
   229 	struct SDes
   230 		{
   231 		TUint8* iSrcAddr;
   232 		TUint8* iDestAddr;
   233 		TInt iCount;
   234 		TUint iControl;
   235 		SDes* iNext;
   236 		};
   237 public:
   238 	static void DoTransfer();
   239 	static void Enable(TInt aIdx);
   240 private:
   241 	static TInt CurrentChannel;
   242 	static TBool IsDescriptorLoaded[KChannelCount];
   243 public:
   244 	// externally accessible pseudo-registers
   245 	static TUint32 ChannelControl[KChannelCount];
   246 	static TUint8* SrcAddr[KChannelCount];
   247 	static TUint8* DestAddr[KChannelCount];
   248 	static TInt Count[KChannelCount];
   249 	static TUint Control[KChannelCount];
   250 	static SDes* NextDes[KChannelCount];
   251 	static TUint32 CompletionInt;
   252 	static TUint32 ErrorInt;
   253 	// hook for pseudo ISR
   254 	static TPseudoIsr Isr;
   255 	// transfer failure simulation
   256 	static TInt FailCount[KChannelCount];
   257 	static TInt InterruptsToMiss[KChannelCount];
   258 	};
   259 
   260 TUint32 DmacSg::ChannelControl[KChannelCount];
   261 TUint8* DmacSg::SrcAddr[KChannelCount];
   262 TUint8* DmacSg::DestAddr[KChannelCount];
   263 TInt DmacSg::Count[KChannelCount];
   264 TUint DmacSg::Control[KChannelCount];
   265 DmacSg::SDes* DmacSg::NextDes[KChannelCount];
   266 TUint32 DmacSg::CompletionInt;
   267 TUint32 DmacSg::ErrorInt;
   268 TPseudoIsr DmacSg::Isr;
   269 TInt DmacSg::FailCount[KChannelCount];
   270 TInt DmacSg::InterruptsToMiss[KChannelCount];
   271 TInt DmacSg::CurrentChannel;
   272 TBool DmacSg::IsDescriptorLoaded[KChannelCount];
   273 
   274 
   275 void DmacSg::DoTransfer()
   276 	{
   277 	if (ChannelControl[CurrentChannel] & EChannelBitRun)
   278 		{
   279 		if (FailCount[CurrentChannel] > 0 && --FailCount[CurrentChannel] == 0)
   280 			{
   281 			ChannelControl[CurrentChannel] &= ~EChannelBitRun;
   282 			ErrorInt |= 1 << CurrentChannel;
   283 			Isr();
   284 			}
   285 		else
   286 			{
   287 			if (IsDescriptorLoaded[CurrentChannel])
   288 				{
   289 				if (Count[CurrentChannel] == 0)
   290 					{
   291 					IsDescriptorLoaded[CurrentChannel] = EFalse;
   292 					if (Control[CurrentChannel] & EDesBitInt)
   293 						{
   294 						if (InterruptsToMiss[CurrentChannel] > 0)
   295 							InterruptsToMiss[CurrentChannel]--;
   296 						else
   297 							{
   298 							CompletionInt |= 1 << CurrentChannel;
   299 							Isr();
   300 							}
   301 						}
   302 					}
   303 				else
   304 					{
   305 					TInt s = Min(Count[CurrentChannel], KBurstSize);
   306 					memcpy(DestAddr[CurrentChannel], SrcAddr[CurrentChannel], s);
   307 					Count[CurrentChannel] -= s;
   308 					SrcAddr[CurrentChannel] += s;
   309 					DestAddr[CurrentChannel] += s;
   310 					}
   311 				}
   312 			// Need to test again as new descriptor must be loaded if
   313 			// completion has just occured.
   314 			if (! IsDescriptorLoaded[CurrentChannel])
   315 				{
   316 				if (NextDes[CurrentChannel] != NULL)
   317 					{
   318 					SrcAddr[CurrentChannel] = NextDes[CurrentChannel]->iSrcAddr;
   319 					DestAddr[CurrentChannel] = NextDes[CurrentChannel]->iDestAddr;
   320 					Count[CurrentChannel] = NextDes[CurrentChannel]->iCount;
   321 					Control[CurrentChannel] = NextDes[CurrentChannel]->iControl;
   322 					NextDes[CurrentChannel] = NextDes[CurrentChannel]->iNext;
   323 					IsDescriptorLoaded[CurrentChannel] = ETrue;
   324 					}
   325 				else
   326 					ChannelControl[CurrentChannel] &= ~EChannelBitRun;
   327 				}
   328 			}
   329 		}
   330 
   331 	CurrentChannel++;
   332 	if (CurrentChannel >= KChannelCount)
   333 		CurrentChannel = 0;
   334 	}
   335 
   336 
   337 void DmacSg::Enable(TInt aIdx)
   338 	{
   339 	SrcAddr[aIdx] = NextDes[aIdx]->iSrcAddr;
   340 	DestAddr[aIdx] = NextDes[aIdx]->iDestAddr;
   341 	Count[aIdx] = NextDes[aIdx]->iCount;
   342 	Control[aIdx] = NextDes[aIdx]->iControl;
   343 	NextDes[aIdx] = NextDes[aIdx]->iNext;
   344 	IsDescriptorLoaded[aIdx] = ETrue;
   345 	ChannelControl[aIdx] |= EChannelBitRun;
   346 	}
   347 
   348 //////////////////////////////////////////////////////////////////////////////
   349 
   350 class DmacSim
   351 /** 
   352  Harness calling the various DMA controller simulators periodically.
   353  */
   354 	{
   355 public:
   356 	static void StartEmulation();
   357 	static void StopEmulation();
   358 private:
   359 	enum { KPeriod = 1 }; // in ms
   360 	static void TickCB(TAny* aThis);
   361 	static NTimer Timer;
   362 	};
   363 
   364 NTimer DmacSim::Timer;
   365 
   366 void DmacSim::StartEmulation()
   367 	{
   368 	new (&Timer) NTimer(&TickCB, 0);
   369 	__DMA_ASSERTA(Timer.OneShot(KPeriod, EFalse) == KErrNone);
   370 	}
   371 
   372 void DmacSim::StopEmulation()
   373 	{
   374 	Timer.Cancel();
   375 	}
   376 
   377 void DmacSim::TickCB(TAny*)
   378 	{
   379 	DmacSb::DoTransfer();
   380 	DmacDb::DoTransfer();
   381 	DmacSg::DoTransfer();
   382 	__DMA_ASSERTA(Timer.Again(KPeriod) == KErrNone);
   383 	}
   384 
   385 //////////////////////////////////////////////////////////////////////////////
   386 // PSL FOR DMA SIMULATION
   387 //////////////////////////////////////////////////////////////////////////////
   388 
   389 class DSimSbController : public TDmac
   390 	{
   391 public:
   392 	DSimSbController();
   393 private:
   394 	static void Isr();
   395 	// from TDmac
   396 	virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
   397 	virtual void StopTransfer(const TDmaChannel& aChannel);
   398 	virtual TInt FailNext(const TDmaChannel& aChannel);
   399 	virtual TBool IsIdle(const TDmaChannel& aChannel);
   400 	virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
   401 	virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
   402 public:
   403 	static const SCreateInfo KInfo;
   404 	TDmaSbChannel iChannels[KChannelCount];
   405 	};
   406 
   407 DSimSbController SbController;
   408 
   409 const TDmac::SCreateInfo DSimSbController::KInfo =
   410 	{
   411 	KChannelCount,
   412 	KDesCount,
   413 	0,
   414 	sizeof(SDmaPseudoDes),
   415 	0,
   416 	};
   417 
   418 DSimSbController::DSimSbController()
   419 	: TDmac(KInfo)
   420 	{
   421 	DmacSb::Isr = Isr;
   422 	}
   423 
   424 
   425 void DSimSbController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
   426 	{
   427 	TUint32 i = aChannel.PslId();
   428 	const SDmaPseudoDes& des = HdrToDes(aHdr);
   429 	DmacSb::SrcAddr[i] = (TUint8*) des.iSrc;
   430 	DmacSb::DestAddr[i] = (TUint8*) des.iDest;
   431 	DmacSb::Count[i] = des.iCount;
   432 	DmacSb::ControlStatus[i] |= DmacSb::ECsRun;
   433 	}
   434 
   435 
   436 void DSimSbController::StopTransfer(const TDmaChannel& aChannel)
   437 	{
   438 	__e32_atomic_and_ord32(&DmacSb::ControlStatus[aChannel.PslId()], (TUint32)~DmacSb::ECsRun);
   439 	}
   440 
   441 
   442 TInt DSimSbController::FailNext(const TDmaChannel& aChannel)
   443 	{
   444 	DmacSb::FailCount[aChannel.PslId()] = 1;
   445 	return KErrNone;
   446 	}
   447 
   448 
   449 TBool DSimSbController::IsIdle(const TDmaChannel& aChannel)
   450 	{
   451 	return (DmacSb::ControlStatus[aChannel.PslId()] & DmacSb::ECsRun) == 0;
   452 	}
   453 
   454 
   455 TInt DSimSbController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
   456 	{
   457 	return KMaxTransferSize;
   458 	}
   459 
   460 
   461 TUint DSimSbController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
   462 	{
   463 	return KMemAlignMask;
   464 	}
   465 
   466 
   467 void DSimSbController::Isr()
   468 	{
   469 	for (TInt i = 0; i < KChannelCount; i++)
   470 		{
   471 		TUint32 mask = (1 << i);
   472 		if (DmacSb::CompletionInt & mask)
   473 			{
   474 			DmacSb::CompletionInt &= ~mask;
   475 			HandleIsr(SbController.iChannels[i], ETrue);
   476 			}
   477 		if (DmacSb::ErrorInt & mask)
   478 			{
   479 			DmacSb::ErrorInt &= ~mask;
   480 			HandleIsr(SbController.iChannels[i], EFalse);
   481 			}
   482 		}
   483 	}
   484 
   485 //////////////////////////////////////////////////////////////////////////////
   486 
   487 class DSimDbController : public TDmac
   488 	{
   489 public:
   490 	DSimDbController();
   491 private:
   492 	static void Isr();
   493 	// from TDmac
   494 	virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
   495 	virtual void StopTransfer(const TDmaChannel& aChannel);
   496 	virtual TInt FailNext(const TDmaChannel& aChannel);
   497 	virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount);
   498 	virtual TBool IsIdle(const TDmaChannel& aChannel);
   499 	virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
   500 	virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
   501 public:
   502 	static const SCreateInfo KInfo;
   503 	TDmaDbChannel iChannels[KChannelCount];
   504 	};
   505 
   506 DSimDbController DbController;
   507 
   508 const TDmac::SCreateInfo DSimDbController::KInfo =
   509 	{
   510 	KChannelCount,
   511 	KDesCount,
   512 	0,
   513 	sizeof(SDmaPseudoDes),
   514 	0,
   515 	};
   516 
   517 
   518 DSimDbController::DSimDbController()
   519 	: TDmac(KInfo)
   520 	{
   521 	DmacDb::Isr = Isr;
   522 	}
   523 
   524 
   525 void DSimDbController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
   526 	{
   527 	TUint32 i = aChannel.PslId();
   528 	const SDmaPseudoDes& des = HdrToDes(aHdr);
   529 	DmacDb::PrgSrcAddr[i] = (TUint8*) des.iSrc;
   530 	DmacDb::PrgDestAddr[i] = (TUint8*) des.iDest;
   531 	DmacDb::PrgCount[i] = des.iCount;
   532 	DmacDb::Enable(i);
   533 	}
   534 
   535 
   536 void DSimDbController::StopTransfer(const TDmaChannel& aChannel)
   537 	{
   538 	__e32_atomic_and_ord32(&DmacDb::ControlStatus[aChannel.PslId()], (TUint32)~(DmacDb::ECsRun|DmacDb::ECsPrg));
   539 	}
   540 
   541 
   542 TInt DSimDbController::FailNext(const TDmaChannel& aChannel)
   543 	{
   544 	DmacDb::FailCount[aChannel.PslId()] = 1;
   545 	return KErrNone;
   546 	}
   547 
   548 
   549 TInt DSimDbController::MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount)
   550 	{
   551 	__DMA_ASSERTD((DmacDb::ControlStatus[aChannel.PslId()] & DmacDb::ECsRun) == 0);
   552 	__DMA_ASSERTD(aInterruptCount >= 0);
   553 	// At most one interrupt can be missed with double-buffer controller
   554 	if (aInterruptCount == 1)
   555 		{
   556 		DmacDb::InterruptsToMiss[aChannel.PslId()] = aInterruptCount;
   557 		return KErrNone;
   558 		}
   559 	else
   560 		return KErrNotSupported;
   561 	}
   562 
   563 
   564 TBool DSimDbController::IsIdle(const TDmaChannel& aChannel)
   565 	{
   566 	return (DmacDb::ControlStatus[aChannel.PslId()] & DmacDb::ECsRun) == 0;
   567 	}
   568 
   569 
   570 TInt DSimDbController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
   571 	{
   572 	return KMaxTransferSize;
   573 	}
   574 
   575 
   576 TUint DSimDbController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
   577 	{
   578 	return KMemAlignMask;
   579 	}
   580 
   581 
   582 void DSimDbController::Isr()
   583 	{
   584 	for (TInt i = 0; i < KChannelCount; i++)
   585 		{
   586 		TUint32 mask = (1 << i);
   587 		if (DmacDb::CompletionInt & mask)
   588 			{
   589 			DmacDb::CompletionInt &= ~mask;
   590 			HandleIsr(DbController.iChannels[i], ETrue);
   591 			}
   592 		if (DmacDb::ErrorInt & mask)
   593 			{
   594 			DmacDb::ErrorInt &= ~mask;
   595 			HandleIsr(DbController.iChannels[i], EFalse);
   596 			}
   597 		}
   598 	}
   599 
   600 //////////////////////////////////////////////////////////////////////////////
   601 
   602 class DSimSgController : public TDmac
   603 	{
   604 public:
   605 	DSimSgController();
   606 private:
   607 	static void Isr();
   608 	// from TDmac
   609 	virtual void Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr);
   610 	virtual void StopTransfer(const TDmaChannel& aChannel);
   611 	virtual TBool IsIdle(const TDmaChannel& aChannel);
   612 	virtual TInt MaxTransferSize(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
   613 	virtual TUint MemAlignMask(TDmaChannel& aChannel, TUint aFlags, TUint32 aPslInfo);
   614 	virtual void InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
   615 						   TUint aFlags, TUint32 aPslInfo, TUint32 aCookie);
   616 	virtual void ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr);
   617 	virtual void AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
   618 							 const SDmaDesHdr& aNewHdr);
   619 	virtual void UnlinkHwDes(const TDmaChannel& aChannel, SDmaDesHdr& aHdr);
   620 	virtual TInt FailNext(const TDmaChannel& aChannel);
   621 	virtual TInt MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount);
   622 private:
   623 	inline DmacSg::SDes* HdrToHwDes(const SDmaDesHdr& aHdr);
   624 public:
   625 	static const SCreateInfo KInfo;
   626 	TDmaSgChannel iChannels[KChannelCount];
   627 	};
   628 
   629 DSimSgController SgController;
   630 
   631 const TDmac::SCreateInfo DSimSgController::KInfo =
   632 	{
   633 	KChannelCount,
   634 	KDesCount,
   635 	KCapsBitHwDes,
   636 	sizeof(DmacSg::SDes),
   637 #ifdef __WINS__
   638 	0,
   639 #else
   640 	EMapAttrSupRw|EMapAttrFullyBlocking,
   641 #endif
   642 	};
   643 
   644 
   645 inline DmacSg::SDes* DSimSgController::HdrToHwDes(const SDmaDesHdr& aHdr)
   646 	{
   647 	return static_cast<DmacSg::SDes*>(TDmac::HdrToHwDes(aHdr));
   648 	}
   649 
   650 
   651 DSimSgController::DSimSgController()
   652 	: TDmac(KInfo)
   653 	{
   654 	DmacSg::Isr = Isr;
   655 	}
   656 
   657 
   658 void DSimSgController::Transfer(const TDmaChannel& aChannel, const SDmaDesHdr& aHdr)
   659 	{
   660 	TUint32 i = aChannel.PslId();
   661 	DmacSg::NextDes[i] = HdrToHwDes(aHdr);
   662 	DmacSg::Enable(i);
   663 	}
   664 
   665 
   666 void DSimSgController::StopTransfer(const TDmaChannel& aChannel)
   667 	{
   668 	__e32_atomic_and_ord32(&DmacSg::ChannelControl[aChannel.PslId()], (TUint32)~DmacSg::EChannelBitRun);
   669 	}
   670 
   671 
   672 void DSimSgController::InitHwDes(const SDmaDesHdr& aHdr, TUint32 aSrc, TUint32 aDest, TInt aCount,
   673 								 TUint /*aFlags*/, TUint32 /*aPslInfo*/, TUint32 /*aCookie*/)
   674 	{
   675 	DmacSg::SDes& des = *HdrToHwDes(aHdr);
   676 	des.iSrcAddr = reinterpret_cast<TUint8*>(aSrc);
   677 	des.iDestAddr = reinterpret_cast<TUint8*>(aDest);
   678 	des.iCount = static_cast<TInt16>(aCount);
   679 	des.iControl |= DmacSg::EDesBitInt;
   680 	des.iNext = NULL;
   681 	}
   682 
   683 
   684 void DSimSgController::ChainHwDes(const SDmaDesHdr& aHdr, const SDmaDesHdr& aNextHdr)
   685 	{
   686 	DmacSg::SDes& des = *HdrToHwDes(aHdr);
   687 	des.iControl &= ~DmacSg::EDesBitInt;
   688 	des.iNext = HdrToHwDes(aNextHdr);
   689 	}
   690 
   691 
   692 void DSimSgController::AppendHwDes(const TDmaChannel& aChannel, const SDmaDesHdr& aLastHdr,
   693 								   const SDmaDesHdr& aNewHdr)
   694 	{
   695 	TUint32 i = aChannel.PslId();
   696 	DmacSg::SDes* pNewDes = HdrToHwDes(aNewHdr);
   697 	TInt prevLevel = NKern::DisableAllInterrupts();
   698 
   699 	if ((DmacSg::ChannelControl[i] & DmacSg::EChannelBitRun) == 0)
   700 		{
   701 		DmacSg::NextDes[i] = pNewDes;
   702 		DmacSg::Enable(i);
   703 		}
   704 	else if (DmacSg::NextDes[i] == NULL)
   705 		DmacSg::NextDes[i] = pNewDes;
   706 	else
   707 		HdrToHwDes(aLastHdr)->iNext = pNewDes;
   708 
   709 	NKern::RestoreInterrupts(prevLevel);
   710 	}
   711 
   712 
   713 void DSimSgController::UnlinkHwDes(const TDmaChannel& /*aChannel*/, SDmaDesHdr& aHdr)
   714 	{
   715   	DmacSg::SDes* pD = HdrToHwDes(aHdr);
   716 	pD->iNext = NULL;
   717 	pD->iControl |= DmacSg::EDesBitInt;
   718 	}
   719 
   720 
   721 TInt DSimSgController::FailNext(const TDmaChannel& aChannel)
   722 	{
   723 	__DMA_ASSERTD((DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0);
   724 	DmacSg::FailCount[aChannel.PslId()] = 1;
   725 	return KErrNone;
   726 	}
   727 
   728 
   729 TInt DSimSgController::MissNextInterrupts(const TDmaChannel& aChannel, TInt aInterruptCount)
   730 	{
   731 	__DMA_ASSERTD((DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0);
   732 	__DMA_ASSERTD(aInterruptCount >= 0);
   733 	DmacSg::InterruptsToMiss[aChannel.PslId()] = aInterruptCount;
   734 	return KErrNone;
   735 	}
   736 
   737 
   738 TBool DSimSgController::IsIdle(const TDmaChannel& aChannel)
   739 	{
   740 	return (DmacSg::ChannelControl[aChannel.PslId()] & DmacSg::EChannelBitRun) == 0;
   741 	}
   742 
   743 
   744 TInt DSimSgController::MaxTransferSize(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
   745 	{
   746 	return KMaxTransferSize;
   747 	}
   748 
   749 
   750 TUint DSimSgController::MemAlignMask(TDmaChannel& /*aChannel*/, TUint /*aFlags*/, TUint32 /*aPslInfo*/)
   751 	{
   752 	return KMemAlignMask;
   753 	}
   754 
   755 
   756 void DSimSgController::Isr()
   757 	{
   758 	for (TInt i = 0; i < KChannelCount; i++)
   759 		{
   760 		TUint32 mask = (1 << i);
   761 		if (DmacSg::CompletionInt & mask)
   762 			{
   763 			DmacSg::CompletionInt &= ~mask;
   764 			HandleIsr(SgController.iChannels[i], ETrue);
   765 			}
   766 		if (DmacSg::ErrorInt & mask)
   767 			{
   768 			DmacSg::ErrorInt &= ~mask;
   769 			HandleIsr(SgController.iChannels[i], EFalse);
   770 			}
   771 		}
   772 	}
   773 
   774 
   775 //////////////////////////////////////////////////////////////////////////////
   776 // Channel opening/closing
   777 
   778 enum TController { ESb=0, EDb=1, ESg=2 };
   779 
   780 const TUint32 KControllerMask = 0x30;
   781 const TUint32 KControllerShift = 4;
   782 const TUint32 KChannelIdxMask = 3;
   783 
   784 #define MKCHN(type, idx) (((type)<<KControllerShift)|idx)
   785 
   786 static TUint32 TestSbChannels[] = { MKCHN(ESb,0), MKCHN(ESb,1), MKCHN(ESb,2), MKCHN(ESb,3) };
   787 static TUint32 TestDbChannels[] = { MKCHN(EDb,0), MKCHN(EDb,1), MKCHN(EDb,2), MKCHN(EDb,3) };
   788 static TUint32 TestSgChannels[] = { MKCHN(ESg,0), MKCHN(ESg,1), MKCHN(ESg,2), MKCHN(ESg,3) };
   789 
   790 static TDmaTestInfo TestInfo =
   791 	{
   792 	KMaxTransferSize,
   793 	KMemAlignMask,
   794 	0,
   795 	KChannelCount,
   796 	TestSbChannels,
   797 	KChannelCount,
   798 	TestDbChannels,
   799 	KChannelCount,
   800 	TestSgChannels,
   801 	};
   802 
   803 EXPORT_C const TDmaTestInfo& DmaTestInfo()
   804 	{
   805 	return TestInfo;
   806 	}
   807 
   808 // Keep track of opened channels so Tick callback used to fake DMA
   809 // transfers is enabled only when necessary.
   810 static TInt OpenChannelCount = 0;
   811 
   812 
   813 TDmaChannel* DmaChannelMgr::Open(TUint32 aOpenId)
   814 	{
   815 	TInt dmac = (aOpenId & KControllerMask) >> KControllerShift;
   816 	__DMA_ASSERTD(dmac < 3);
   817 	TInt i = aOpenId & KChannelIdxMask;
   818 	TDmaChannel* pC = NULL;
   819 	TDmac* controller = NULL;
   820 	switch (dmac)
   821 		{
   822 	case ESb:
   823 		pC = SbController.iChannels + i;
   824 		controller = &SbController;
   825 		break;
   826 	case EDb:
   827 		pC = DbController.iChannels + i;
   828 		controller = &DbController;
   829 		break;
   830 	case ESg:
   831 		pC = SgController.iChannels + i;
   832 		controller = &SgController;
   833 		break;
   834 	default:
   835 		__DMA_CANT_HAPPEN();
   836 		}
   837 
   838 	if (++OpenChannelCount == 1)
   839 		{
   840 		__KTRACE_OPT(KDMA, Kern::Printf("Enabling DMA simulation"));
   841 		DmacSim::StartEmulation();
   842 		}
   843 	if (pC->IsOpened())
   844 		return NULL;
   845 	pC->iController = controller;
   846 	pC->iPslId = i;
   847 	return pC;
   848 	}
   849 
   850 
   851 void DmaChannelMgr::Close(TDmaChannel* /*aChannel*/)
   852 	{
   853 	if (--OpenChannelCount == 0)
   854 		{
   855 		DmacSim::StopEmulation();
   856 		__KTRACE_OPT(KDMA, Kern::Printf("Stopping DMA simulation"));
   857 		}
   858 	}
   859 
   860 TInt DmaChannelMgr::StaticExtension(TInt /*aCmd*/, TAny* /*aArg*/)
   861 	{
   862 	return KErrNotSupported;
   863 	}
   864 
   865 //////////////////////////////////////////////////////////////////////////////
   866 
   867 //
   868 // On hardware, this code is inside a kernel extension.
   869 //
   870 
   871 DECLARE_STANDARD_EXTENSION()
   872 	{
   873 	__KTRACE_OPT(KDMA, Kern::Printf("Starting DMA simulator..."));
   874 	TInt r;
   875 	r = SbController.Create(DSimSbController::KInfo);
   876 	if (r != KErrNone)
   877 		return r;
   878 	r = DbController.Create(DSimDbController::KInfo);
   879 	if (r != KErrNone)
   880 		return r;
   881 	r = SgController.Create(DSimSgController::KInfo);
   882 	if (r != KErrNone)
   883 		return r;
   884 
   885 	return KErrNone;
   886 	}
   887 
   888 //
   889 // On WINS, this code is inside a LDD (see mmp file) so we need some
   890 // bootstrapping code to call the kernel extension entry point.
   891 //
   892 
   893 class DDummyLdd : public DLogicalDevice
   894 	{
   895 public:
   896 	// from DLogicalDevice
   897 	TInt Install();
   898 	void GetCaps(TDes8& aDes) const;
   899 	TInt Create(DLogicalChannelBase*& aChannel);
   900 	};
   901 
   902 TInt DDummyLdd::Create(DLogicalChannelBase*& aChannel)
   903     {
   904 	aChannel=NULL;
   905 	return KErrNone;
   906     }
   907 
   908 TInt DDummyLdd::Install()
   909     {
   910 	_LIT(KLddName, "DmaSim");
   911     TInt r = SetName(&KLddName);
   912 	if (r == KErrNone)
   913 		r = InitExtension();
   914 	return r;
   915     }
   916 
   917 void DDummyLdd::GetCaps(TDes8& /*aDes*/) const
   918     {
   919     }
   920 
   921 EXPORT_C DLogicalDevice* CreateLogicalDevice()
   922 	{
   923     return new DDummyLdd;
   924 	}
   925 
   926 
   927 //---