|
1 // Copyright (c) 2008-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/iic/iic_client.cpp |
|
15 // Simulated (kernel-side) client of IIC Platform Independent Layer (PIL) |
|
16 // |
|
17 #include <kernel/kern_priv.h> // for DThread, TDfc |
|
18 #ifdef STANDALONE_CHANNEL |
|
19 #include <drivers/iic_transaction.h> |
|
20 #else |
|
21 #include <drivers/iic.h> |
|
22 #endif |
|
23 #include "../t_iic.h" |
|
24 #ifdef STANDALONE_CHANNEL |
|
25 #include <drivers/iic_channel.h> |
|
26 #include "i2c.h" |
|
27 #include "spi.h" |
|
28 #endif |
|
29 |
|
30 #ifdef LOG_CLIENT |
|
31 #define CLIENT_PRINT(str) Kern::Printf str |
|
32 #else |
|
33 #define CLIENT_PRINT(str) |
|
34 #endif |
|
35 |
|
36 const TInt KIicClientThreadPriority = 24; |
|
37 const TInt KIicSlaveClientDfcPriority = 3; // 0 to 7, 7 is highest ... for MasterSlave functionality |
|
38 |
|
39 const TInt KMaxNumChannels = 3; // 1 SPI and 2 I2C |
|
40 |
|
41 // Define an array of channel that the client is going to create. |
|
42 // For iic_client, it needs SPI channels for Master tests, and I2c channels for MasterSlave tests. |
|
43 #ifdef STANDALONE_CHANNEL |
|
44 |
|
45 const TUint NUM_CHANNELS_SPI = 4; // Arbitrary |
|
46 const TInt KChannelTypeArraySpi[NUM_CHANNELS_SPI] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMaster}; |
|
47 #define CHANNEL_TYPE_SPI(n) (KChannelTypeArraySpi[n]) |
|
48 const DIicBusChannel::TChannelDuplex KChannelDuplexArraySpi[NUM_CHANNELS_SPI] = {DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EFullDuplex}; |
|
49 #define CHANNEL_DUPLEX_SPI(n) (KChannelDuplexArraySpi[n]) |
|
50 #define BUS_TYPE_SPI (DIicBusChannel::ESpi) |
|
51 |
|
52 #define NUM_CHANNELS_I2C 3 |
|
53 #if defined(MASTER_MODE) && !defined(SLAVE_MODE) |
|
54 const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::EMaster}; |
|
55 #elif defined(MASTER_MODE) && defined(SLAVE_MODE) |
|
56 const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMasterSlave}; |
|
57 #else |
|
58 const TInt KChannelTypeArrayI2c[NUM_CHANNELS_I2C] = {DIicBusChannel::ESlave, DIicBusChannel::ESlave, DIicBusChannel::ESlave}; |
|
59 #endif |
|
60 #define CHANNEL_TYPE_I2C(n) (KChannelTypeArrayI2c[n]) |
|
61 #define CHANNEL_DUPLEX_I2C(n) (DIicBusChannel::EHalfDuplex) |
|
62 #define BUS_TYPE_I2C (DIicBusChannel::EI2c) |
|
63 |
|
64 const TInt8 KSpiChannelNumBase = 1; // Arbitrary, real platform may consult the Configuration Repository |
|
65 // Note limit of 5 bit representation (0-31) |
|
66 |
|
67 LOCAL_C TInt8 AssignChanNumSpi() |
|
68 { |
|
69 static TInt8 iBaseChanNumSpi = KSpiChannelNumBase; |
|
70 CLIENT_PRINT(("SPI AssignChanNum - on entry, iBaseCanNum = 0x%x\n",iBaseChanNumSpi)); |
|
71 return iBaseChanNumSpi++; // Arbitrary, for illustration |
|
72 } |
|
73 |
|
74 #if defined(MASTER_MODE) |
|
75 const TInt8 KI2cChannelNumBase = 10; // Arbitrary, real platform may consult the Configuration Repository |
|
76 // Note limit of 5 bit representation (0-31) |
|
77 |
|
78 #else |
|
79 const TInt8 KI2cChannelNumBase = 10 + NUM_CHANNELS; // For Slave mode, want to provide different response |
|
80 // If client assumes Master mode, should be informed not available |
|
81 #endif |
|
82 |
|
83 LOCAL_C TInt8 AssignChanNumI2c() |
|
84 { |
|
85 static TInt8 iBaseChanNumI2c = KI2cChannelNumBase; |
|
86 CLIENT_PRINT(("I2C AssignChanNum - on entry, iBaseChanNum = 0x%x\n",iBaseChanNumI2c)); |
|
87 return iBaseChanNumI2c++; // Arbitrary, for illustration |
|
88 } |
|
89 |
|
90 class DIicClientChan : public DBase |
|
91 { |
|
92 public: |
|
93 DIicClientChan(DIicBusChannel* aChan, TInt8 aChanNum, TUint8 aChanType):iChan(aChan),iChanNumber(aChanNum),iChanType(aChanType){}; |
|
94 ~DIicClientChan(); |
|
95 TInt GetChanNum()const {return iChanNumber;}; |
|
96 TUint8 GetChanType()const {return iChanType;}; |
|
97 DIicBusChannel* GetChannelPtr(){return iChan;}; |
|
98 inline DIicClientChan& operator=(DIicClientChan& aChan) {iChanNumber=aChan.iChanNumber; iChanType=aChan.iChanType; iChan=aChan.iChan; return *this;}; |
|
99 inline TInt operator==(DIicClientChan& aChan) {if((iChanNumber == aChan.iChanNumber)&&(iChanType == aChan.iChanType)&&(iChan == aChan.iChan)) return 1;return 0;}; |
|
100 private: |
|
101 TInt iChanNumber; |
|
102 TUint8 iChanType; |
|
103 DIicBusChannel* iChan; |
|
104 }; |
|
105 |
|
106 DIicClientChan::~DIicClientChan() |
|
107 { |
|
108 delete iChan; |
|
109 } |
|
110 |
|
111 #endif /*STANDALONE_CHANNEL*/ |
|
112 |
|
113 |
|
114 #ifdef STANDALONE_CHANNEL |
|
115 _LIT(KLddRootName,"iic_client_ctrless"); |
|
116 #else |
|
117 _LIT(KLddRootName,"iic_client"); |
|
118 #endif |
|
119 _LIT(KIicClientThreadName,"IicClientLddThread"); |
|
120 |
|
121 struct TCapsIicClient |
|
122 { |
|
123 TVersion version; |
|
124 }; |
|
125 |
|
126 struct TTransStatusPair |
|
127 { |
|
128 TRequestStatus* iReq; |
|
129 TIicBusTransaction* iTrans; |
|
130 }; |
|
131 |
|
132 struct TTransCbPair |
|
133 { |
|
134 TIicBusTransaction* iTrans; |
|
135 TIicBusCallback* iCb; |
|
136 }; |
|
137 |
|
138 struct TExtractInfo |
|
139 { |
|
140 TExtractInfo(){iBufPtr = NULL; iTfer = NULL;} |
|
141 ~TExtractInfo(){delete iBufPtr; delete iTfer;} |
|
142 TDes8* iBufPtr; |
|
143 TIicBusTransfer* iTfer; |
|
144 TIicBusTransaction* iTrans; |
|
145 }; |
|
146 |
|
147 struct TTransBufReuseData |
|
148 { |
|
149 // Convenience for testing, only - retain pointers to private data |
|
150 // so that it can be re-used from a callback. |
|
151 TIicBusTransaction* iTransaction; |
|
152 TIicBusTransfer* iHdTfer; |
|
153 TIicBusTransfer* iFdTfer; |
|
154 TDes8* iHdr; |
|
155 // Pointer to callback object (for cleanup) |
|
156 TIicBusCallback* iCallback; |
|
157 }; |
|
158 |
|
159 class DDeviceIicClient : public DLogicalDevice |
|
160 { |
|
161 public: |
|
162 /** |
|
163 * The constructor |
|
164 */ |
|
165 DDeviceIicClient(); |
|
166 /** |
|
167 * The destructor |
|
168 */ |
|
169 ~DDeviceIicClient(); |
|
170 /** |
|
171 * Second stage constructor - install the device |
|
172 */ |
|
173 virtual TInt Install(); |
|
174 /** |
|
175 * Get the Capabilites of the device |
|
176 * @param aDes descriptor that will contain the returned capibilites |
|
177 */ |
|
178 virtual void GetCaps(TDes8 &aDes) const; |
|
179 /** |
|
180 * Create a logical channel to the device |
|
181 */ |
|
182 virtual TInt Create(DLogicalChannelBase*& aChannel); |
|
183 |
|
184 public: |
|
185 }; |
|
186 |
|
187 #ifdef STANDALONE_CHANNEL |
|
188 /*This class is used to test the set and get inline functions |
|
189 * of DIicBusChannel Interface. |
|
190 * */ |
|
191 class TTestIicChannelInterface: public DIicBusChannel |
|
192 { |
|
193 public: |
|
194 TTestIicChannelInterface(TChannelType aChannelType, TBusType aBusType, TChannelDuplex aChanDuplex); |
|
195 ~TTestIicChannelInterface(){}; |
|
196 TInt DoCreate(){return 0;}; |
|
197 TInt CheckHdr(TDes8* /*aHdr*/){return 0;}; |
|
198 TInt TestInterface(); |
|
199 private: |
|
200 TBool TestChannelType(DIicBusChannel::TChannelType aType ); |
|
201 TBool TestBusType(DIicBusChannel::TBusType aType ); |
|
202 TBool TestDuplexType(DIicBusChannel::TChannelDuplex aType ); |
|
203 }; |
|
204 |
|
205 TTestIicChannelInterface::TTestIicChannelInterface(TChannelType aChannelType, TBusType aBusType, TChannelDuplex aChanDuplex) |
|
206 : DIicBusChannel(aChannelType, aBusType, aChanDuplex) |
|
207 {} |
|
208 |
|
209 TBool TTestIicChannelInterface::TestChannelType(DIicBusChannel::TChannelType aType) |
|
210 { |
|
211 CLIENT_PRINT(("Setting channel type 0x%x\n", aType)); |
|
212 SetChannelType(aType); |
|
213 if(aType != ChannelType()) |
|
214 { |
|
215 CLIENT_PRINT(("ERROR: Mismatch, looking for channel 0x%x but found 0x%x\n", aType, ChannelType())); |
|
216 return EFalse; |
|
217 } |
|
218 else |
|
219 { |
|
220 CLIENT_PRINT(("Looking for channel 0x%x and found 0x%x\n", aType, ChannelType())); |
|
221 } |
|
222 return ETrue; |
|
223 } |
|
224 |
|
225 TBool TTestIicChannelInterface::TestBusType(DIicBusChannel::TBusType aType) |
|
226 { |
|
227 CLIENT_PRINT(("Setting Bus type 0x%x\n", aType)); |
|
228 SetBusType(aType); |
|
229 if(aType != BusType()) |
|
230 { |
|
231 CLIENT_PRINT(("ERROR: Mismatch, looking for Bus 0x%x but found 0x%x\n", aType, BusType())); |
|
232 return EFalse; |
|
233 } |
|
234 else |
|
235 { |
|
236 CLIENT_PRINT(("Looking for Bus 0x%x and found 0x%x\n", aType, BusType())); |
|
237 } |
|
238 return ETrue; |
|
239 } |
|
240 |
|
241 TBool TTestIicChannelInterface::TestDuplexType(DIicBusChannel::TChannelDuplex aType) |
|
242 { |
|
243 CLIENT_PRINT(("Setting duplex channel type 0x%x\n", aType)); |
|
244 SetChannelType(aType); |
|
245 if(aType != ChannelDuplex()) |
|
246 { |
|
247 CLIENT_PRINT(("ERROR: Mismatch, looking for duplex channel 0x%x but found 0x%x\n", aType, ChannelDuplex())); |
|
248 return EFalse; |
|
249 } |
|
250 else |
|
251 { |
|
252 CLIENT_PRINT(("Looking for Duplex Channel 0x%x and found 0x%x\n", aType, ChannelDuplex())); |
|
253 } |
|
254 return ETrue; |
|
255 } |
|
256 |
|
257 TInt TTestIicChannelInterface::TestInterface() |
|
258 { |
|
259 |
|
260 RArray <DIicBusChannel::TChannelType> chtype; |
|
261 RArray <DIicBusChannel::TBusType> bustype; |
|
262 RArray <DIicBusChannel::TChannelDuplex> dutype; |
|
263 |
|
264 chtype.Append(DIicBusChannel::EMaster); |
|
265 chtype.Append(DIicBusChannel::ESlave); |
|
266 chtype.Append(DIicBusChannel::EMasterSlave); |
|
267 |
|
268 bustype.Append(DIicBusChannel::EI2c); |
|
269 bustype.Append(DIicBusChannel::ESpi); |
|
270 bustype.Append(DIicBusChannel::EMicrowire); |
|
271 bustype.Append(DIicBusChannel::ECci); |
|
272 bustype.Append(DIicBusChannel::ESccb); |
|
273 |
|
274 dutype.Append(DIicBusChannel::EHalfDuplex); |
|
275 dutype.Append(DIicBusChannel::EFullDuplex); |
|
276 |
|
277 int result = KErrNone; |
|
278 int count = chtype.Count(); |
|
279 int i=0; |
|
280 |
|
281 CLIENT_PRINT(("\nCheck Master/Slave channel setting\n")); |
|
282 CLIENT_PRINT(("\nChannel MASK = 0x%x\n", KChannelTypeMask)); |
|
283 for(i=0; i< count; ++i) |
|
284 { |
|
285 if(!TestChannelType(chtype[i])) |
|
286 { |
|
287 result = KErrGeneral; |
|
288 break; |
|
289 } |
|
290 } |
|
291 CLIENT_PRINT(("\nCheck Master/Slave channel setting from higher bit number to lower, reverse enum.\n")); |
|
292 for(i=count-1; i >= 0; --i) |
|
293 { |
|
294 if(!TestChannelType(chtype[i])) |
|
295 { |
|
296 result = KErrGeneral; |
|
297 break; |
|
298 } |
|
299 } |
|
300 |
|
301 CLIENT_PRINT(("\nCheck Channel Bus type settings\n")); |
|
302 CLIENT_PRINT(("\nBus MASK = 0x%x\n", KBusTypeMask)); |
|
303 count = bustype.Count(); |
|
304 for(i=0; i< count; ++i) |
|
305 { |
|
306 if(!TestBusType(bustype[i])) |
|
307 { |
|
308 result = KErrGeneral; |
|
309 break; |
|
310 } |
|
311 } |
|
312 CLIENT_PRINT(("\nCheck Channel Bus type settings from higher bit number to lower, reverse enum.\n")); |
|
313 for(i = count-1; i >= 0; --i) |
|
314 { |
|
315 if(!TestBusType(bustype[i])) |
|
316 { |
|
317 result = KErrGeneral; |
|
318 break; |
|
319 } |
|
320 } |
|
321 CLIENT_PRINT(("\nCheck Channel Duplex settings\n")); |
|
322 CLIENT_PRINT(("\nDuplex MASK = 0x%x\n", KChannelDuplexMask)); |
|
323 count = dutype.Count(); |
|
324 for(i=0; i < count; ++i) |
|
325 { |
|
326 if(!TestDuplexType(dutype[i])) |
|
327 { |
|
328 result = KErrGeneral; |
|
329 break; |
|
330 } |
|
331 } |
|
332 CLIENT_PRINT(("\nCheck Channel Duplex setting from higher bit number to lower, reverse enum.\n")); |
|
333 for(i = count-1; i >= 0; --i) |
|
334 { |
|
335 if(!TestDuplexType(dutype[i])) |
|
336 { |
|
337 result = KErrGeneral; |
|
338 break; |
|
339 } |
|
340 } |
|
341 chtype.Close(); |
|
342 dutype.Close(); |
|
343 bustype.Close(); |
|
344 return result; |
|
345 } |
|
346 #endif //STANDALONE_CHANNEL |
|
347 |
|
348 class DChannelIicClient : public DLogicalChannel |
|
349 { |
|
350 public: |
|
351 DChannelIicClient(); |
|
352 ~DChannelIicClient(); |
|
353 |
|
354 TInt CleanupExtractTrans(TIicBusTransaction *aTrans); |
|
355 |
|
356 TInt InitIicClient(); |
|
357 |
|
358 virtual TInt DoCreate(TInt aUnit, const TDesC8* aInfo, const TVersion& aVer); |
|
359 |
|
360 protected: |
|
361 virtual void HandleMsg(TMessageBase* aMsg); // Note: this is a pure virtual in DLogicalChannel |
|
362 |
|
363 void DoCancel(TInt aMask); // Name for convenience! |
|
364 TInt DoControl(TInt aId, TAny* a1, TAny* a2); // Name for convenience! |
|
365 TInt DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2); // Name for convenience! |
|
366 |
|
367 void TestTransModification(TIicBusTransaction* aTransaction, // public to be accessed by callback |
|
368 TIicBusTransfer* aHdTfer, |
|
369 TIicBusTransfer* aFdTfer, |
|
370 TDes8* aHdr); |
|
371 #ifdef STANDALONE_CHANNEL |
|
372 public: |
|
373 static TInt OrderEntries(const DIicClientChan& aMatch, const DIicClientChan& aEntry); |
|
374 #endif |
|
375 private: |
|
376 TInt ExtractTransData(TUsideTracnDesc* aUsideTrancnDesc, TIicBusTransaction*& aTrans); |
|
377 TInt CreateTransferListHalfDuplex( |
|
378 TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1, |
|
379 TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2, |
|
380 TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3); |
|
381 TInt CreateTransferListFullDuplex( |
|
382 TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1, |
|
383 TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2, |
|
384 TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3); |
|
385 |
|
386 |
|
387 TInt DeleteFullDuplexTest(TIicBusTransaction *aTrans); |
|
388 |
|
389 TInt DoCreateFullDuplexTransTest(TInt aTestType); |
|
390 |
|
391 TInt DoPriorityTest(TInt aBusId); |
|
392 TInt ConstructTransactionOne(TIicBusTransaction*& aTrans); |
|
393 void CleanupTransactionOne(TIicBusTransaction*& aTrans); |
|
394 |
|
395 |
|
396 TInt InsertPairs(TTransStatusPair* aPair, TTransCbPair* aCbPair); |
|
397 |
|
398 TInt CreateDefaultSpiBuf(TConfigSpiBufV01*& aBuf); |
|
399 |
|
400 //Add new functions for controller-less mode |
|
401 TInt QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback *aCallback=NULL); |
|
402 TInt CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction); |
|
403 TInt StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2); |
|
404 TInt CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch=NULL); |
|
405 TInt ReleaseChannel(TInt aChannelId); |
|
406 public: |
|
407 inline void Lock() {Kern::MutexWait(*iArrayMutex);} |
|
408 inline void Unlock() {Kern::MutexSignal(*iArrayMutex);} |
|
409 inline void GetWriteAccess() {Kern::SemaphoreWait(*iChanArrWrtSem);} // aNTicks not specified = wait forever |
|
410 inline void FreeWriteAccess() {Kern::SemaphoreSignal(*iChanArrWrtSem);} |
|
411 |
|
412 void CleanupTransaction(TIicBusTransaction*& aTrans); // public for access by callback |
|
413 |
|
414 static TIicBusTransaction* MultiTranscCallbackFunc(TIicBusTransaction* aTrans, TAny* aParam); |
|
415 |
|
416 static void TransModifCallback(TIicBusTransaction* aTrans, TInt aBusId, TInt aResult, TAny* aParam); |
|
417 |
|
418 private: |
|
419 TDynamicDfcQue* iDfcQue; |
|
420 |
|
421 DMutex* iArrayMutex; // used to protect array of channels |
|
422 DSemaphore* iChanArrWrtSem; // used to synchronise write access to iChannelArray |
|
423 |
|
424 // Used for Transaction One |
|
425 HBuf8* buf1; |
|
426 HBuf8* buf2; |
|
427 HBuf8* buf3; |
|
428 HBuf8* buf4; |
|
429 HBuf8* buf5; |
|
430 HBuf8* buf6; |
|
431 TIicBusTransfer* tfer1; |
|
432 TIicBusTransfer* tfer2; |
|
433 TIicBusTransfer* tfer3; |
|
434 TIicBusTransfer* tfer4; |
|
435 TIicBusTransfer* tfer5; |
|
436 TIicBusTransfer* tfer6; |
|
437 TIicBusTransfer* tfer7; |
|
438 HBuf8* header; |
|
439 HBuf8* header2; |
|
440 HBuf8* header3; |
|
441 HBuf8* header4; |
|
442 HBuf8* header5; |
|
443 HBuf8* headerBlock; |
|
444 TConfigSpiBufV01* spiHeader; |
|
445 |
|
446 |
|
447 static TIicBusTransaction* iMultiTransac; |
|
448 |
|
449 // Used for simple transactions |
|
450 TIicBusTransaction* iTrans; |
|
451 TConfigSpiBufV01* iSpiBuf; |
|
452 TConfigI2cBufV01* iI2cBuf; |
|
453 TIicBusTransfer* iTfer; |
|
454 TIicBusTransactionPreamble* iTransPreamble; |
|
455 TIicBusTransfer* iFdTfer; |
|
456 |
|
457 public: |
|
458 DThread* iClient; |
|
459 RPointerArray<TTransStatusPair> iTransStatArrayByTrans; |
|
460 RPointerArray<TTransStatusPair> iTransStatArrayByStatus; |
|
461 RPointerArray<TTransCbPair> iTransCbArrayByTrans; |
|
462 RPointerArray<TExtractInfo> iExtractInfoArray; |
|
463 |
|
464 // Support for Preamble testing |
|
465 TRequestStatus* iPreambleStatus; |
|
466 TRequestStatus* iMultiTranscStatus; |
|
467 |
|
468 // Support for buffer re-use testing |
|
469 TTransBufReuseData iTransBufReuseData; |
|
470 |
|
471 // Support for MasterSlave processing |
|
472 private: |
|
473 TInt InitSlaveClient(); |
|
474 |
|
475 private: |
|
476 HBuf8* iConfigHdr; |
|
477 TRequestStatus* iStatus; |
|
478 |
|
479 public: |
|
480 void RequestComplete(TInt r); |
|
481 |
|
482 public: |
|
483 TIicBusSlaveCallback* iNotif; // public to be accessible by callback |
|
484 TInt iChannelId; // public to be accessible by callback |
|
485 TInt* iClientChanId; |
|
486 |
|
487 #ifdef STANDALONE_CHANNEL |
|
488 //Used to store the captured channel |
|
489 struct TCapturedChannel |
|
490 { |
|
491 DIicClientChan* iChanPtr; |
|
492 TInt iChannelId; |
|
493 }; |
|
494 TCapturedChannel iCapturedChannel; |
|
495 #endif |
|
496 }; |
|
497 |
|
498 DDeviceIicClient::DDeviceIicClient() |
|
499 // Constructor |
|
500 { |
|
501 CLIENT_PRINT(("> DDeviceIicClient::DDeviceIicClient()")); |
|
502 __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::DDeviceIicClient()")); |
|
503 iParseMask=0; // No info, no PDD, no Units |
|
504 iUnitsMask=0; |
|
505 iVersion=TVersion(KIicClientMajorVersionNumber, |
|
506 KIicClientMinorVersionNumber, |
|
507 KIicClientBuildVersionNumber); |
|
508 } |
|
509 #ifdef STANDALONE_CHANNEL |
|
510 // auxiliary function for ordering entries in the array of channels |
|
511 TInt DChannelIicClient::OrderEntries(const DIicClientChan& aMatch, const DIicClientChan& aEntry) |
|
512 { |
|
513 TUint8 l=(TUint8)aMatch.GetChanNum(); |
|
514 TUint8 r=(TUint8)aEntry.GetChanNum(); |
|
515 if(l<r) |
|
516 return -1; |
|
517 else if(l>r) |
|
518 return 1; |
|
519 else |
|
520 return 0; |
|
521 } |
|
522 // global ordering object to be passed to RPointerArray InsertInOrderXXX and FindInOrder |
|
523 TLinearOrder<DIicClientChan> EntryOrder(DChannelIicClient::OrderEntries); |
|
524 |
|
525 // Store all the channels created by the client |
|
526 RPointerArray<DIicClientChan> ChannelArray; |
|
527 #endif /*STANDALONE_CHANNEL*/ |
|
528 |
|
529 DDeviceIicClient::~DDeviceIicClient() |
|
530 { |
|
531 CLIENT_PRINT(("> DDeviceIicClient::~DDeviceIicClient()")); |
|
532 __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::~DDeviceIicClient()")); |
|
533 #ifdef STANDALONE_CHANNEL |
|
534 //For Standalone Channel, the client is responsible for channel destroy |
|
535 ChannelArray.ResetAndDestroy(); |
|
536 #endif |
|
537 } |
|
538 |
|
539 TInt DDeviceIicClient::Install() |
|
540 // Install the device driver. |
|
541 { |
|
542 CLIENT_PRINT(("> DDeviceIicClient::Install()")); |
|
543 __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DDeviceIicClient::Install()")); |
|
544 return(SetName(&KLddRootName)); |
|
545 } |
|
546 |
|
547 // Auxiliary functions for ordering entries in the array of TTransStatusPair pointers |
|
548 // The first is to enable searching by Transaction (used by the callback) |
|
549 // The second is to enable searching by the TRequestStatus (used by cancel calls) |
|
550 TInt OrderEntriesByTrans(const TTransStatusPair& aMatch, const TTransStatusPair& aEntry) |
|
551 { |
|
552 TUint l=(TUint)(aMatch.iTrans); |
|
553 TUint r=(TUint)(aEntry.iTrans); |
|
554 if(l>r) |
|
555 return -1; |
|
556 else if(l<r) |
|
557 return 1; |
|
558 else |
|
559 return 0; |
|
560 } |
|
561 TLinearOrder<TTransStatusPair> TransStatusOrderByTrans(OrderEntriesByTrans); |
|
562 |
|
563 TInt OrderEntriesByStatus(const TTransStatusPair& aMatch, const TTransStatusPair& aEntry) |
|
564 { |
|
565 TUint l=(TUint)(aMatch.iReq); |
|
566 TUint r=(TUint)(aEntry.iReq); |
|
567 if(l>r) |
|
568 return -1; |
|
569 else if(l<r) |
|
570 return 1; |
|
571 else |
|
572 return 0; |
|
573 } |
|
574 TLinearOrder<TTransStatusPair> TransStatusOrderByStatus(OrderEntriesByStatus); |
|
575 |
|
576 // Auxilliary function to track callback objects assigned to asynchronous transactions |
|
577 TInt OrderCbEntriesByTrans(const TTransCbPair& aMatch, const TTransCbPair& aEntry) |
|
578 { |
|
579 TUint l=(TUint)(aMatch.iTrans); |
|
580 TUint r=(TUint)(aEntry.iTrans); |
|
581 if(l>r) |
|
582 return -1; |
|
583 else if(l<r) |
|
584 return 1; |
|
585 else |
|
586 return 0; |
|
587 } |
|
588 TLinearOrder<TTransCbPair> TransCbOrderByTrans(OrderCbEntriesByTrans); |
|
589 |
|
590 TInt OrderExtractInfoByTrans(const TExtractInfo& aMatch, const TExtractInfo& aEntry) |
|
591 { |
|
592 TUint l=(TUint)(aMatch.iTrans); |
|
593 TUint r=(TUint)(aEntry.iTrans); |
|
594 if(l>r) |
|
595 return -1; |
|
596 else if(l<r) |
|
597 return 1; |
|
598 else |
|
599 return 0; |
|
600 } |
|
601 TLinearOrder<TExtractInfo> ExtractInfoOrderByTrans(OrderExtractInfoByTrans); |
|
602 |
|
603 |
|
604 _LIT(KLitArrayMutexName,"IIC_CLIENT_ARRAY_MUTEX"); |
|
605 _LIT(KLitArraySemName,"IIC_CLIENT_ARRAY_SEM"); |
|
606 #define IIC_CLIENT_MUTEX_ORDER KMutexOrdGeneral4 // Semi-arbitrary - middle of general purpose range, allow higher and lower priorities |
|
607 |
|
608 TInt DChannelIicClient::InitIicClient() |
|
609 { |
|
610 TInt r = Kern::MutexCreate(iArrayMutex,KLitArrayMutexName,IIC_CLIENT_MUTEX_ORDER); |
|
611 if(r!=KErrNone) |
|
612 return r; |
|
613 r = Kern::SemaphoreCreate(iChanArrWrtSem,KLitArraySemName,1); // Initial count of one allows first wait to be non-blocking |
|
614 if(r!=KErrNone) |
|
615 iArrayMutex->Close(NULL); |
|
616 |
|
617 return r; |
|
618 } |
|
619 |
|
620 TInt DChannelIicClient::InsertPairs(TTransStatusPair* aPair, TTransCbPair* aCbPair) |
|
621 { |
|
622 CLIENT_PRINT(("DChannelIicClient::InsertPairs invoked with aPair=0x%x, aPair->iReq=0x%x, aPair-iTrans=0x%x\n",aPair,aPair->iReq,aPair->iTrans )); |
|
623 CLIENT_PRINT(("DChannelIicClient::InsertPairs ... and aCbPair=0x%x, aCbPair->iCb=0x%x, aCbPair-iTrans=0x%x\n",aCbPair,aCbPair->iCb,aCbPair->iTrans )); |
|
624 TInt r = KErrNone; |
|
625 |
|
626 GetWriteAccess(); |
|
627 Lock(); |
|
628 |
|
629 if((r = iTransStatArrayByTrans.InsertInOrder(aPair,TransStatusOrderByTrans)) == KErrNone) |
|
630 { |
|
631 if((r = iTransStatArrayByStatus.InsertInOrder(aPair,TransStatusOrderByStatus)) == KErrNone) |
|
632 { |
|
633 if((r = iTransCbArrayByTrans.InsertInOrder(aCbPair,TransCbOrderByTrans))!=KErrNone) |
|
634 { |
|
635 CLIENT_PRINT(("DChannelIicClient::InsertPairs, aCbPair=0x%x InsertInOrder(status) returned %d\n",aCbPair,r)); |
|
636 } |
|
637 } |
|
638 else |
|
639 { |
|
640 CLIENT_PRINT(("DChannelIicClient::InsertPairs, aPair=0x%x InsertInOrder(status) returned %d\n",aPair,r)); |
|
641 } |
|
642 } |
|
643 else |
|
644 { |
|
645 CLIENT_PRINT(("DChannelIicClient::InsertPairs, aPair=0x%x InsertInOrder(trans) returned %d\n",aPair,r)); |
|
646 } |
|
647 FreeWriteAccess(); |
|
648 Unlock(); |
|
649 return r; |
|
650 } |
|
651 |
|
652 //dummy call back func is provided for asyn call in priority test |
|
653 static void DummyCallbackFunc(TIicBusTransaction* /*aTrans*/, TInt /*aBusId*/, TInt /*aResult*/, TAny* /*aParam*/) |
|
654 { |
|
655 //do nothing |
|
656 } |
|
657 |
|
658 static void AsyncCallbackFunc(TIicBusTransaction* aTrans, TInt aBusId, TInt aResult, TAny* aParam) |
|
659 { |
|
660 (void)aBusId; // aBusId is not used if CLIENT_PRINT is disabled |
|
661 CLIENT_PRINT(("> AsyncCallbackFunc() - aTrans=0x%x, aBusId=0x%x, aResult=%d, aParam=0x%x\n",aTrans,aBusId,aResult,aParam)); |
|
662 DChannelIicClient* channel = (DChannelIicClient*)aParam; |
|
663 CLIENT_PRINT(("AsyncCallbackFunc() - channel=0x%x\n",channel)); |
|
664 |
|
665 // Use the channel to get the user-side client's TRequestStatus and complete it with aResult |
|
666 TTransStatusPair* searchPair = new TTransStatusPair(); |
|
667 searchPair->iTrans = aTrans; |
|
668 channel->GetWriteAccess(); |
|
669 channel->Lock(); |
|
670 TInt pairIndex = (channel->iTransStatArrayByTrans).FindInOrder(searchPair,TransStatusOrderByTrans); |
|
671 delete searchPair; |
|
672 if(pairIndex<0) |
|
673 { |
|
674 CLIENT_PRINT(("AsyncCallbackFunc() - (trans) FindInOrder returned %d (aTrans=0x%x)\n",pairIndex,aTrans)); |
|
675 return; |
|
676 } |
|
677 TTransStatusPair* pairPtr = (channel->iTransStatArrayByTrans)[pairIndex]; |
|
678 TRequestStatus* status = pairPtr->iReq; |
|
679 |
|
680 // Now remove the TTransStatusPair objects in iTransStatArrayByTrans, iTransStatArrayByStatus |
|
681 (channel->iTransStatArrayByTrans).Remove(pairIndex); |
|
682 pairIndex = (channel->iTransStatArrayByStatus).FindInOrder(pairPtr,TransStatusOrderByStatus); |
|
683 if(pairIndex<0) |
|
684 { |
|
685 CLIENT_PRINT(("AsyncCallbackFunc() - (status) FindInOrder returned %d (status=0x%x)\n",pairIndex,status)); |
|
686 return; |
|
687 } |
|
688 (channel->iTransStatArrayByStatus).Remove(pairIndex); |
|
689 |
|
690 // Now remove the TTransCbPair object in iTransCbArrayByTrans |
|
691 TTransCbPair* SearchCbPair = new TTransCbPair(); |
|
692 SearchCbPair->iTrans = aTrans; |
|
693 pairIndex = (channel->iTransCbArrayByTrans).FindInOrder(SearchCbPair,TransCbOrderByTrans); |
|
694 delete SearchCbPair; |
|
695 if(pairIndex<0) |
|
696 { |
|
697 CLIENT_PRINT(("AsyncCallbackFunc() - (cb) FindInOrder returned %d (aTrans=0x%x)\n",pairIndex,aTrans)); |
|
698 return; |
|
699 } |
|
700 TTransCbPair* cbPair = (channel->iTransCbArrayByTrans)[pairIndex]; |
|
701 (channel->iTransCbArrayByTrans).Remove(pairIndex); |
|
702 delete cbPair->iCb; |
|
703 delete cbPair; |
|
704 channel->FreeWriteAccess(); |
|
705 channel->Unlock(); |
|
706 Kern::RequestComplete(channel->iClient, status, aResult); |
|
707 // We should call CleanupExtractTrans() to delete all the objects created in ExtractTransData() |
|
708 channel->CleanupExtractTrans(pairPtr->iTrans); |
|
709 // The object referred to be pairPtr is finished with and can be deleted |
|
710 channel->CleanupTransaction(pairPtr->iTrans); |
|
711 delete pairPtr; |
|
712 } |
|
713 |
|
714 |
|
715 void DDeviceIicClient::GetCaps(TDes8& aDes) const |
|
716 // Return the IicClient capabilities. |
|
717 { |
|
718 CLIENT_PRINT(("> DDeviceIicClient::GetCaps(TDes8& aDes) const")); |
|
719 TPckgBuf<TCapsIicClient> b; |
|
720 b().version=TVersion(KIicClientMajorVersionNumber, |
|
721 KIicClientMinorVersionNumber, |
|
722 KIicClientBuildVersionNumber); |
|
723 Kern::InfoCopy(aDes,b); |
|
724 } |
|
725 |
|
726 |
|
727 TInt DDeviceIicClient::Create(DLogicalChannelBase*& aChannel) |
|
728 // Create a channel on the device. |
|
729 { |
|
730 CLIENT_PRINT(("> DDeviceIicClient::Create(DLogicalChannelBase*& aChannel)")); |
|
731 if(iOpenChannels>=KMaxNumChannels) |
|
732 return KErrOverflow; |
|
733 aChannel=new DChannelIicClient; |
|
734 return aChannel?KErrNone:KErrNoMemory; |
|
735 } |
|
736 |
|
737 #ifdef STANDALONE_CHANNEL |
|
738 |
|
739 TInt GetChanPtr(const TInt aBusId, TInt &aIndex, DIicClientChan*& aChan) |
|
740 { |
|
741 __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, aBusId=0x%x\n",aBusId)); |
|
742 TInt32 chanId; |
|
743 chanId = GET_CHAN_NUM(aBusId); |
|
744 __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, chanId=0x%x\n",chanId)); |
|
745 DIicClientChan chanEntry(NULL,(TInt8)chanId, DIicBusChannel::EMasterSlave); |
|
746 TInt r = KErrNotFound; |
|
747 aIndex = ChannelArray.FindInOrder(&chanEntry, EntryOrder); |
|
748 if(aIndex >= 0) |
|
749 { |
|
750 aChan = ChannelArray[aIndex]; |
|
751 r = KErrNone; |
|
752 } |
|
753 |
|
754 __KTRACE_OPT(KIIC, Kern::Printf("GetChanPtr, chanPtr=0x%x, index=%d\n",aChan,aIndex)); |
|
755 return r; |
|
756 } |
|
757 #endif |
|
758 |
|
759 DECLARE_STANDARD_LDD() |
|
760 { |
|
761 //If in STANDALONE_CHANNEL mode, the client creates a list of channels |
|
762 #ifdef STANDALONE_CHANNEL |
|
763 DIicClientChan* aClientChan; |
|
764 TInt r = KErrNone; |
|
765 DIicBusChannel *chan = NULL, *chanM = NULL, *chanS = NULL; |
|
766 TInt i; |
|
767 for(i=0; i<NUM_CHANNELS_SPI; i++) |
|
768 { |
|
769 CLIENT_PRINT(("\n")); |
|
770 #if defined(MASTER_MODE) |
|
771 if(CHANNEL_TYPE_SPI(i) == (DIicBusChannel::EMaster)) |
|
772 { |
|
773 chan=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i)); |
|
774 if(!chan) |
|
775 { |
|
776 CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i)); |
|
777 return NULL; |
|
778 } |
|
779 CLIENT_PRINT(("SPI chan created at 0x%x\n",chan)); |
|
780 if(((DSimulatedIicBusChannelMasterSpi*)chan)->Create()!=KErrNone) |
|
781 { |
|
782 delete chan; |
|
783 return NULL; |
|
784 } |
|
785 aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::EMaster); |
|
786 if(!aClientChan) |
|
787 { |
|
788 delete chan; |
|
789 return NULL; |
|
790 } |
|
791 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder); |
|
792 if(r!=KErrNone) |
|
793 { |
|
794 delete chan; |
|
795 delete aClientChan; |
|
796 break; |
|
797 } |
|
798 } |
|
799 #endif |
|
800 #if defined(MASTER_MODE) && defined(SLAVE_MODE) |
|
801 if(CHANNEL_TYPE_SPI(i) == DIicBusChannel::EMasterSlave) |
|
802 { |
|
803 //For MasterSlave channel, the client creates a Master channel, a Slave |
|
804 //channel and a MasterSlave Channel, then store all of them in ChannelArray. |
|
805 chanM=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i)); |
|
806 if(!chanM) |
|
807 return NULL; |
|
808 |
|
809 chanS=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i)); |
|
810 if(!chanS) |
|
811 { |
|
812 delete chanM; |
|
813 return NULL; |
|
814 } |
|
815 chan=new DIicBusChannelMasterSlave(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i),(DSimulatedIicBusChannelMasterSpi*)chanM,(DSimulatedIicBusChannelSlaveSpi*)chanS); // Generic implementation |
|
816 if(!chan) |
|
817 { |
|
818 CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i)); |
|
819 delete chanM; |
|
820 delete chanS; |
|
821 return NULL; |
|
822 } |
|
823 CLIENT_PRINT(("SPI chan created at 0x%x\n",chan)); |
|
824 if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone) |
|
825 { |
|
826 delete chanM; |
|
827 delete chanS; |
|
828 delete chan; |
|
829 return NULL; |
|
830 } |
|
831 aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::EMasterSlave); |
|
832 if(!aClientChan) |
|
833 { |
|
834 delete chanM; |
|
835 delete chanS; |
|
836 delete chan; |
|
837 return NULL; |
|
838 } |
|
839 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder); |
|
840 if(r!=KErrNone) |
|
841 { |
|
842 delete chanM; |
|
843 delete chanS; |
|
844 delete chan; |
|
845 delete aClientChan; |
|
846 break; |
|
847 } |
|
848 } |
|
849 #endif |
|
850 #if defined(SLAVE_MODE) |
|
851 if(CHANNEL_TYPE_SPI(i) == (DIicBusChannel::ESlave)) |
|
852 { |
|
853 chan=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE_SPI,CHANNEL_DUPLEX_SPI(i)); |
|
854 if(!chan) |
|
855 { |
|
856 CLIENT_PRINT(("\n\nSpi: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_SPI(i),i)); |
|
857 return NULL; |
|
858 } |
|
859 CLIENT_PRINT(("SPI chan created at 0x%x\n",chan)); |
|
860 if(((DSimulatedIicBusChannelSlaveSpi*)chan)->Create()!=KErrNone) |
|
861 { |
|
862 delete chan; |
|
863 return NULL; |
|
864 } |
|
865 aClientChan = new DIicClientChan(chan,AssignChanNumSpi(),DIicBusChannel::ESlave); |
|
866 if(!aClientChan) |
|
867 { |
|
868 delete chan; |
|
869 return NULL; |
|
870 } |
|
871 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder); |
|
872 if(r!=KErrNone) |
|
873 { |
|
874 delete chan; |
|
875 delete aClientChan; |
|
876 break; |
|
877 } |
|
878 } |
|
879 #endif |
|
880 #if !defined(MASTER_MODE) && !defined(SLAVE_MODE) |
|
881 #error I2C mode not defined as Master, Slave nor Master-Slave |
|
882 #endif |
|
883 } |
|
884 |
|
885 for(i=0; i<NUM_CHANNELS_I2C; i++) |
|
886 { |
|
887 CLIENT_PRINT(("\n")); |
|
888 #if defined(MASTER_MODE) |
|
889 if(CHANNEL_TYPE_I2C(i) == (DIicBusChannel::EMaster)) |
|
890 { |
|
891 chan=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i)); |
|
892 if(!chan) |
|
893 { |
|
894 CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_I2C(i),i)); |
|
895 return NULL; |
|
896 } |
|
897 CLIENT_PRINT(("I2C chan created at 0x%x\n",chan)); |
|
898 if(((DSimulatedIicBusChannelMasterI2c*)chan)->Create()!=KErrNone) |
|
899 { |
|
900 delete chan; |
|
901 return NULL; |
|
902 } |
|
903 aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMaster); |
|
904 if(!aClientChan) |
|
905 { |
|
906 delete chan; |
|
907 return NULL; |
|
908 } |
|
909 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder); |
|
910 if(r!=KErrNone) |
|
911 { |
|
912 delete chan; |
|
913 delete aClientChan; |
|
914 break; |
|
915 } |
|
916 } |
|
917 #endif |
|
918 #if defined(MASTER_MODE) && defined(SLAVE_MODE) |
|
919 if(CHANNEL_TYPE_I2C(i) == DIicBusChannel::EMasterSlave) |
|
920 { |
|
921 chanM=new DSimulatedIicBusChannelMasterI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i)); |
|
922 if(!chanM) |
|
923 return NULL; |
|
924 |
|
925 chanS=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i)); |
|
926 if(!chanS) |
|
927 { |
|
928 delete chanM; |
|
929 return NULL; |
|
930 } |
|
931 //The client doesn't create the Master and Slave channels, as they should be created |
|
932 //in MasterSlave channel's DoCreate(). |
|
933 chan=new DSimulatedIicBusChannelMasterSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i),(DSimulatedIicBusChannelMasterI2c*)chanM,(DSimulatedIicBusChannelSlaveI2c*)chanS); // Generic implementation |
|
934 if(!chan) |
|
935 { |
|
936 CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_I2C(i),i)); |
|
937 delete chanM; |
|
938 delete chanS; |
|
939 return NULL; |
|
940 } |
|
941 CLIENT_PRINT(("I2C chan created at 0x%x\n",chan)); |
|
942 if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone) |
|
943 { |
|
944 delete chanM; |
|
945 delete chanS; |
|
946 delete chan; |
|
947 return NULL; |
|
948 } |
|
949 aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::EMasterSlave); |
|
950 if(!aClientChan) |
|
951 { |
|
952 delete chanM; |
|
953 delete chanS; |
|
954 delete chan; |
|
955 return NULL; |
|
956 } |
|
957 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder); |
|
958 if(r!=KErrNone) |
|
959 { |
|
960 delete chanM; |
|
961 delete chanS; |
|
962 delete chan; |
|
963 delete aClientChan; |
|
964 break; |
|
965 } |
|
966 } |
|
967 #endif |
|
968 #if defined(SLAVE_MODE) |
|
969 if(CHANNEL_TYPE_I2C(i) == (DIicBusChannel::ESlave)) |
|
970 { |
|
971 chan=new DSimulatedIicBusChannelSlaveI2c(BUS_TYPE_I2C,CHANNEL_DUPLEX_I2C(i)); |
|
972 if(!chan) |
|
973 { |
|
974 CLIENT_PRINT(("\n\nI2C: Channel of type (%d) not created for index %d\n\n",CHANNEL_TYPE_I2C(i),i)); |
|
975 return NULL; |
|
976 } |
|
977 CLIENT_PRINT(("I2C chan created at 0x%x\n",chan)); |
|
978 if(((DSimulatedIicBusChannelSlaveI2c*)chan)->Create()!=KErrNone) |
|
979 { |
|
980 delete chan; |
|
981 return NULL; |
|
982 } |
|
983 aClientChan = new DIicClientChan(chan,AssignChanNumI2c(),DIicBusChannel::ESlave); |
|
984 if(!aClientChan) |
|
985 { |
|
986 delete chan; |
|
987 return NULL; |
|
988 } |
|
989 r = ChannelArray.InsertInOrder(aClientChan,EntryOrder); |
|
990 if(r!=KErrNone) |
|
991 { |
|
992 delete chan; |
|
993 delete aClientChan; |
|
994 break; |
|
995 } |
|
996 } |
|
997 #endif |
|
998 #if !defined(MASTER_MODE) && !defined(SLAVE_MODE) |
|
999 #error I2C mode not defined as Master, Slave nor Master-Slave |
|
1000 #endif |
|
1001 } |
|
1002 |
|
1003 #endif |
|
1004 return new DDeviceIicClient; |
|
1005 } |
|
1006 |
|
1007 |
|
1008 |
|
1009 DChannelIicClient::DChannelIicClient() |
|
1010 // Constructor |
|
1011 { |
|
1012 CLIENT_PRINT(("> DChannelIicClient::DChannelIicClient()")); |
|
1013 iClient=&Kern::CurrentThread(); |
|
1014 // Increase the DThread's ref count so that it does not close without us |
|
1015 iClient->Open(); |
|
1016 } |
|
1017 |
|
1018 DChannelIicClient::~DChannelIicClient() |
|
1019 // Destructor |
|
1020 { |
|
1021 CLIENT_PRINT(("> DChannelIicClient::~DChannelIicClient()")); |
|
1022 __KTRACE_OPT(KRESMANAGER, Kern::Printf("> DChannelIicClient::~DChannelIicClient()")); |
|
1023 delete iNotif; |
|
1024 iArrayMutex->Close(NULL); |
|
1025 iChanArrWrtSem->Close(NULL); |
|
1026 iDfcQue->Destroy(); |
|
1027 // decrement the DThread's reference count |
|
1028 Kern::SafeClose((DObject*&)iClient, NULL); |
|
1029 |
|
1030 iTransStatArrayByTrans.Reset(); |
|
1031 iTransStatArrayByStatus.Reset(); |
|
1032 iTransCbArrayByTrans.Reset(); |
|
1033 iExtractInfoArray.Reset(); |
|
1034 } |
|
1035 |
|
1036 |
|
1037 TInt DChannelIicClient::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& /*aVer*/) |
|
1038 { |
|
1039 CLIENT_PRINT(("> DChannelIicClient::DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion &aVer)")); |
|
1040 TInt r = Kern::DynamicDfcQCreate(iDfcQue,KIicClientThreadPriority,KIicClientThreadName); |
|
1041 if(r!=KErrNone) |
|
1042 return r; |
|
1043 SetDfcQ(iDfcQue); |
|
1044 iMsgQ.Receive(); |
|
1045 |
|
1046 r = InitIicClient(); |
|
1047 return r; |
|
1048 } |
|
1049 |
|
1050 void DChannelIicClient::HandleMsg(TMessageBase* aMsg) |
|
1051 { |
|
1052 TThreadMessage& m=*(TThreadMessage*)aMsg; |
|
1053 TInt id=m.iValue; |
|
1054 |
|
1055 CLIENT_PRINT((" >ldd: DChannelIicClient::HandleMsg(TMessageBase* aMsg) id=%d\n", id)); |
|
1056 |
|
1057 if (id == (TInt)ECloseMsg) |
|
1058 { |
|
1059 iMsgQ.iMessage->Complete(KErrNone,EFalse); |
|
1060 return; |
|
1061 } |
|
1062 else if (id == KMaxTInt) |
|
1063 { |
|
1064 DoCancel(m.Int0()); |
|
1065 m.Complete(KErrNone,ETrue); |
|
1066 return; |
|
1067 } |
|
1068 |
|
1069 if (id<0) |
|
1070 { |
|
1071 TRequestStatus* pS=(TRequestStatus*)m.Ptr0(); |
|
1072 TInt r=DoRequest(~id, pS, m.Ptr1(), m.Ptr2()); |
|
1073 if (r!=KErrNone) |
|
1074 { |
|
1075 Kern::RequestComplete(iClient, pS, r); |
|
1076 } |
|
1077 m.Complete(KErrNone,ETrue); |
|
1078 } |
|
1079 else |
|
1080 { |
|
1081 TInt r=DoControl(id,m.Ptr0(),m.Ptr1()); |
|
1082 m.Complete(r,ETrue); |
|
1083 } |
|
1084 } |
|
1085 |
|
1086 TInt DChannelIicClient::QueueTransaction(TInt aBusId, TIicBusTransaction* aTransaction, TIicBusCallback *aCallback/*NULL*/) |
|
1087 { |
|
1088 TInt r = KErrNone; |
|
1089 #ifndef STANDALONE_CHANNEL |
|
1090 if(!aCallback) |
|
1091 r = IicBus::QueueTransaction(aBusId, aTransaction); |
|
1092 else |
|
1093 r = IicBus::QueueTransaction(aBusId, aTransaction, aCallback); |
|
1094 #else |
|
1095 __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::QueueTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction)); |
|
1096 if(!aTransaction) |
|
1097 { |
|
1098 return KErrArgument; |
|
1099 } |
|
1100 |
|
1101 // Get a pointer to the channel |
|
1102 TInt dumInt = 0; |
|
1103 DIicClientChan* chanPtr = NULL; |
|
1104 r = GetChanPtr(aBusId, dumInt, chanPtr); |
|
1105 if(r == KErrNone) |
|
1106 { |
|
1107 if(!chanPtr) |
|
1108 { |
|
1109 r = KErrArgument; |
|
1110 } |
|
1111 else |
|
1112 { |
|
1113 switch(chanPtr->GetChanType()) |
|
1114 { |
|
1115 // QueueTransaction requests are only supported by channels in Master mode. |
|
1116 case DIicBusChannel::ESlave: |
|
1117 { |
|
1118 r = KErrNotSupported; |
|
1119 break; |
|
1120 } |
|
1121 // If the request is supported by the Master channel, send it to the channel for processing in its thread |
|
1122 case DIicBusChannel::EMasterSlave: |
|
1123 { |
|
1124 |
|
1125 aTransaction->iBusId = aBusId; |
|
1126 if(!aCallback) |
|
1127 r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction)); |
|
1128 else |
|
1129 r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction, aCallback)); |
|
1130 break; |
|
1131 } |
|
1132 case DIicBusChannel::EMaster: |
|
1133 { |
|
1134 aTransaction->iBusId = aBusId; |
|
1135 if(!aCallback) |
|
1136 r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction)); |
|
1137 else |
|
1138 r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->QueueTransaction(aTransaction, aCallback)); |
|
1139 break; |
|
1140 } |
|
1141 default: |
|
1142 { |
|
1143 r = KErrGeneral; |
|
1144 } |
|
1145 } |
|
1146 } |
|
1147 } |
|
1148 #endif |
|
1149 return r; |
|
1150 } |
|
1151 |
|
1152 TInt DChannelIicClient::CancelTransaction(TInt aBusId, TIicBusTransaction* aTransaction) |
|
1153 { |
|
1154 TInt r = KErrNone; |
|
1155 #ifndef STANDALONE_CHANNEL |
|
1156 r = IicBus::CancelTransaction(aBusId, aTransaction); |
|
1157 #else |
|
1158 __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::CancelTransaction, aBusId=0x%x,aTransaction=0x%x\n", aBusId, aTransaction)); |
|
1159 if(!aTransaction) |
|
1160 { |
|
1161 return KErrArgument; |
|
1162 } |
|
1163 |
|
1164 // Get the channel |
|
1165 TInt dumInt = 0; |
|
1166 DIicClientChan* chanPtr = NULL; |
|
1167 if(r == KErrNone) |
|
1168 { |
|
1169 r = GetChanPtr(aBusId, dumInt, chanPtr); |
|
1170 if(r == KErrNone) |
|
1171 { |
|
1172 if(!chanPtr) |
|
1173 { |
|
1174 r = KErrArgument; |
|
1175 } |
|
1176 else |
|
1177 { |
|
1178 // QueueTransaction requests are only supported by channels in Master mode. |
|
1179 switch(chanPtr->GetChanType()) |
|
1180 { |
|
1181 case DIicBusChannel::ESlave: |
|
1182 { |
|
1183 r = KErrNotSupported; |
|
1184 break; |
|
1185 } |
|
1186 case DIicBusChannel::EMasterSlave: |
|
1187 { |
|
1188 r = (((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CancelTransaction(aTransaction)); |
|
1189 break; |
|
1190 } |
|
1191 case DIicBusChannel::EMaster: |
|
1192 { |
|
1193 r = (((DIicBusChannelMaster*) (chanPtr->GetChannelPtr()))->CancelTransaction(aTransaction)); |
|
1194 break; |
|
1195 } |
|
1196 default: |
|
1197 { |
|
1198 r = KErrGeneral; |
|
1199 } |
|
1200 } |
|
1201 } |
|
1202 } |
|
1203 } |
|
1204 #endif |
|
1205 return r; |
|
1206 } |
|
1207 |
|
1208 |
|
1209 TInt DChannelIicClient::StaticExtension(TUint aId, TUint aFunction, TAny* aParam1, TAny* aParam2) |
|
1210 { |
|
1211 TInt r = KErrNone; |
|
1212 #ifndef STANDALONE_CHANNEL |
|
1213 r = IicBus::StaticExtension(aId, aFunction, aParam1, aParam2); |
|
1214 #else |
|
1215 // Get the channel |
|
1216 TInt dumInt = 0; |
|
1217 DIicClientChan* chanPtr = NULL; |
|
1218 if(r == KErrNone) |
|
1219 { |
|
1220 r = GetChanPtr(aId, dumInt, chanPtr); |
|
1221 if(r == KErrNone) |
|
1222 { |
|
1223 if(!chanPtr) |
|
1224 { |
|
1225 r = KErrArgument; |
|
1226 } |
|
1227 else |
|
1228 { |
|
1229 r = (chanPtr->GetChannelPtr())->StaticExtension(aFunction, aParam1, aParam2); |
|
1230 } |
|
1231 } |
|
1232 } |
|
1233 #endif |
|
1234 return r; |
|
1235 } |
|
1236 |
|
1237 TInt DChannelIicClient::CaptureChannel(TInt aBusId, TDes8* aConfigHdr, TIicBusSlaveCallback* aCallback, TInt& aChannelId, TBool aAsynch) |
|
1238 { |
|
1239 TInt r = KErrNone; |
|
1240 #ifndef STANDALONE_CHANNEL |
|
1241 r = IicBus::CaptureChannel(aBusId, aConfigHdr, aCallback, aChannelId, aAsynch); |
|
1242 #else |
|
1243 // Check that that aCallback!=NULL and aConfigHdr!=NULL - if not, return KErrArgument |
|
1244 if(!aCallback || !aConfigHdr) |
|
1245 { |
|
1246 return KErrArgument; |
|
1247 } |
|
1248 |
|
1249 // Get the channel |
|
1250 TInt chanIndex = 0; |
|
1251 DIicClientChan* chanPtr = NULL; |
|
1252 if(r == KErrNone) |
|
1253 { |
|
1254 r = GetChanPtr(aBusId, chanIndex, chanPtr); |
|
1255 if(r == KErrNone) |
|
1256 { |
|
1257 if(!chanPtr) |
|
1258 { |
|
1259 r = KErrArgument; |
|
1260 } |
|
1261 else |
|
1262 { |
|
1263 switch(chanPtr->GetChanType()) |
|
1264 { |
|
1265 // CaptureChannel requests are only supported by channels in Slave mode. |
|
1266 case DIicBusChannel::EMaster: |
|
1267 { |
|
1268 r = KErrNotSupported; |
|
1269 break; |
|
1270 } |
|
1271 case DIicBusChannel::EMasterSlave: |
|
1272 { |
|
1273 r = ((DIicBusChannelMasterSlave*) (chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch); |
|
1274 break; |
|
1275 } |
|
1276 case DIicBusChannel::ESlave: |
|
1277 { |
|
1278 r = ((DIicBusChannelSlave*)(chanPtr->GetChannelPtr()))->CaptureChannel(aConfigHdr, aCallback, aChannelId, aAsynch); |
|
1279 break; |
|
1280 } |
|
1281 default: |
|
1282 { |
|
1283 r = KErrArgument; |
|
1284 } |
|
1285 } |
|
1286 // For synchronous capture, if successful then install the channel |
|
1287 if(r == KErrNone) |
|
1288 { |
|
1289 if(!aAsynch) |
|
1290 { |
|
1291 iCapturedChannel.iChanPtr = chanPtr; |
|
1292 iCapturedChannel.iChannelId = iChannelId; |
|
1293 } |
|
1294 else |
|
1295 //For asynchronous capture, record chanPtr, if later failed capture, |
|
1296 //clean iCapturedChannel in client's callback. |
|
1297 iCapturedChannel.iChanPtr = chanPtr; |
|
1298 } |
|
1299 } |
|
1300 } |
|
1301 } |
|
1302 #endif |
|
1303 return r; |
|
1304 } |
|
1305 |
|
1306 TInt DChannelIicClient::ReleaseChannel(TInt aChannelId) |
|
1307 { |
|
1308 TInt r = KErrNone; |
|
1309 #ifndef STANDALONE_CHANNEL |
|
1310 r = IicBus::ReleaseChannel(aChannelId); |
|
1311 #else |
|
1312 __KTRACE_OPT(KIIC, Kern::Printf("DChannelIicClient::ReleaseChannel, channelID = 0x%x \n",aChannelId)); |
|
1313 if(iCapturedChannel.iChannelId != aChannelId) |
|
1314 return KErrNotFound; |
|
1315 |
|
1316 if((iCapturedChannel.iChanPtr)->GetChanType() == DIicBusChannel::EMasterSlave) |
|
1317 r = ((DIicBusChannelMasterSlave*)((iCapturedChannel.iChanPtr)->GetChannelPtr()))->ReleaseChannel(); |
|
1318 else if((iCapturedChannel.iChanPtr)->GetChanType() == DIicBusChannel::ESlave) |
|
1319 r = ((DIicBusChannelSlave*)((iCapturedChannel.iChanPtr)->GetChannelPtr()))->ReleaseChannel(); |
|
1320 //After release channel, reset iCapturedChan |
|
1321 iCapturedChannel.iChanPtr = NULL; |
|
1322 iCapturedChannel.iChannelId = 0; |
|
1323 #endif |
|
1324 return r; |
|
1325 } |
|
1326 |
|
1327 void DChannelIicClient::DoCancel(TInt aMask) |
|
1328 { |
|
1329 // Cancel an outstanding request. |
|
1330 CLIENT_PRINT(("DChannelIicClient::DoCancel invoked with aMask=0x%x\n", aMask)); |
|
1331 |
|
1332 // inline void CancelAsyncOperation(TRequestStatus* aStatus, TInt aBusId) {TInt* parms[2]; parms[0]=(TInt*)aStatus; parms[1]=(TInt*)aBusId;DoCancel((TInt)&parms[0]);} |
|
1333 // aMask has the address on TInt* parms[2] |
|
1334 // parms[0] = TRequestStatus pointer |
|
1335 // parms[1] = Bus Identifier |
|
1336 TInt* parms[2]; |
|
1337 TInt r=Kern::ThreadRawRead(iClient,(TAny*)aMask,&(parms[0]),2*sizeof(TInt*)); |
|
1338 if(r!=KErrNone) |
|
1339 { |
|
1340 CLIENT_PRINT(("DChannelIicClient::DoCancel ERROR - Can't read parms[]\n")); |
|
1341 return; // Can't proceed if can't access request parameters |
|
1342 } |
|
1343 CLIENT_PRINT(("DChannelIicClient::DoCancel - TRequestStatus 0x%x, BusID = 0x%x\n",parms[0],parms[1])); |
|
1344 |
|
1345 TTransStatusPair* searchPair = new TTransStatusPair(); |
|
1346 TTransCbPair* cbPair = new TTransCbPair(); |
|
1347 searchPair->iReq = (TRequestStatus*)(parms[0]); |
|
1348 |
|
1349 GetWriteAccess(); |
|
1350 Lock(); |
|
1351 |
|
1352 TInt pairIndexByStatus = iTransStatArrayByStatus.FindInOrder(searchPair,TransStatusOrderByStatus); |
|
1353 CLIENT_PRINT(("DChannelIicClient::DoCancel - pairIndexByStatus=0x%x\n",pairIndexByStatus)); |
|
1354 TInt pairIndexByTrans = KErrNotFound; |
|
1355 |
|
1356 if(pairIndexByStatus<0) |
|
1357 { |
|
1358 // If the TRequestStatus object is not found then either the value was invalid or |
|
1359 // the object may already have been completed. |
|
1360 FreeWriteAccess(); |
|
1361 Unlock(); |
|
1362 CLIENT_PRINT(("DChannelIicClient::DoCancel() - (status) FindInOrder returned %d (status=0x%x)\n",pairIndexByStatus,parms[0])); |
|
1363 } |
|
1364 else |
|
1365 { |
|
1366 // The status-transaction pair exists in the status-index array - so remove it |
|
1367 TTransStatusPair* pairPtrStatus = iTransStatArrayByStatus[pairIndexByStatus]; |
|
1368 iTransStatArrayByStatus.Remove(pairIndexByStatus); |
|
1369 |
|
1370 pairIndexByTrans = iTransStatArrayByTrans.FindInOrder(pairPtrStatus,TransStatusOrderByTrans); |
|
1371 CLIENT_PRINT(("DChannelIicClient::DoCancel - pairIndexByTrans=0x%x\n",pairIndexByTrans)); |
|
1372 if(pairIndexByTrans>=0) |
|
1373 { |
|
1374 iTransStatArrayByTrans.Remove(pairIndexByTrans); |
|
1375 } |
|
1376 FreeWriteAccess(); |
|
1377 Unlock(); |
|
1378 |
|
1379 CLIENT_PRINT(("DChannelIicClient::DoCancel pairPtrStatus=0x%x\n", pairPtrStatus)); |
|
1380 |
|
1381 // Allow the bus to perform any required processing |
|
1382 TIicBusTransaction* trans = pairPtrStatus->iTrans; |
|
1383 CLIENT_PRINT(("DChannelIicClient::CancelTransaction - invoking with busId=0x%x, trans=0x%x\n",(TInt)(parms[1]),trans)); |
|
1384 r = CancelTransaction((TInt)(parms[1]), trans); |
|
1385 cbPair->iTrans=trans; |
|
1386 TInt cbIndex = iTransCbArrayByTrans.FindInOrder(cbPair,TransCbOrderByTrans); |
|
1387 TTransCbPair* theCbPair = iTransCbArrayByTrans[cbIndex]; |
|
1388 TIicBusCallback* cb= (iTransCbArrayByTrans[cbIndex])->iCb; |
|
1389 iTransCbArrayByTrans.Remove(cbIndex); |
|
1390 |
|
1391 // Complete the TRequestStatus object according to the returned value |
|
1392 TRequestStatus* status= (TRequestStatus*)(parms[0]); |
|
1393 Kern::RequestComplete(iClient, status, r); |
|
1394 |
|
1395 // Clean up |
|
1396 delete cb; |
|
1397 delete theCbPair; |
|
1398 // We should call CleanupExtractTrans() to delete all the objects we created in ExtractTransData() |
|
1399 CleanupExtractTrans(trans); |
|
1400 CleanupTransaction(trans); |
|
1401 delete pairPtrStatus; |
|
1402 } |
|
1403 |
|
1404 delete cbPair; |
|
1405 delete searchPair; |
|
1406 |
|
1407 return; |
|
1408 } |
|
1409 |
|
1410 |
|
1411 // Function to support preamble testing |
|
1412 void PreambleCallbackFunc(TIicBusTransaction* /*aTrans*/, TAny* aParam) |
|
1413 { |
|
1414 CLIENT_PRINT(("IIC Client: PreambleCallbackFunc invoked\n")); |
|
1415 // aParam is the address of the client that created the transaction object |
|
1416 __ASSERT_ALWAYS(aParam!=NULL,Kern::Fault("PreambleCallbackFunc, client address ==NULL",__LINE__)); |
|
1417 DChannelIicClient *client = (DChannelIicClient*)aParam; |
|
1418 __ASSERT_ALWAYS(client->iClient!=NULL,Kern::Fault("PreambleCallbackFunc, iClient==NULL",__LINE__)); |
|
1419 __ASSERT_ALWAYS(client->iPreambleStatus!=NULL,Kern::Fault("PreambleCallbackFunc, iPreambleStatus==NULL",__LINE__)); |
|
1420 Kern::RequestComplete(client->iClient, client->iPreambleStatus, KErrNone); |
|
1421 } |
|
1422 |
|
1423 TIicBusTransaction* DChannelIicClient::iMultiTransac; |
|
1424 |
|
1425 // Function to support multi transc testing |
|
1426 TIicBusTransaction* DChannelIicClient::MultiTranscCallbackFunc(TIicBusTransaction* /*aTrans*/, TAny* aParam) |
|
1427 { |
|
1428 CLIENT_PRINT(("IIC Client: MultiTranscCallbackFunc invoked\n")); |
|
1429 // aParam is the address of the client that created the transaction object |
|
1430 __ASSERT_ALWAYS(aParam!=NULL,Kern::Fault("MultiTranscCallbackFunc, client address ==NULL",__LINE__)); |
|
1431 DChannelIicClient *client = (DChannelIicClient*)aParam; |
|
1432 __ASSERT_ALWAYS(client->iClient!=NULL,Kern::Fault("MultiTranscCallbackFunc, iClient==NULL",__LINE__)); |
|
1433 __ASSERT_ALWAYS(client->iMultiTranscStatus!=NULL,Kern::Fault("MultiTranscCallbackFunc, iMultiTranscStatus==NULL",__LINE__)); |
|
1434 Kern::RequestComplete(client->iClient, client->iMultiTranscStatus, KErrNone); |
|
1435 return iMultiTransac; |
|
1436 } |
|
1437 |
|
1438 TInt DChannelIicClient::CleanupExtractTrans(TIicBusTransaction* aTrans) |
|
1439 { |
|
1440 // Clean up the data created in ExtractTransData() |
|
1441 TExtractInfo *extractInfo = new TExtractInfo(); |
|
1442 extractInfo->iTrans = aTrans; |
|
1443 TInt index = iExtractInfoArray.FindInOrder(extractInfo, ExtractInfoOrderByTrans); |
|
1444 if(index >= 0) |
|
1445 { |
|
1446 delete iExtractInfoArray[index]; |
|
1447 iExtractInfoArray.Remove(index); |
|
1448 } |
|
1449 delete extractInfo; |
|
1450 return KErrNone; |
|
1451 } |
|
1452 |
|
1453 TInt DChannelIicClient::ExtractTransData(TUsideTracnDesc* aUsideTrancnDesc, TIicBusTransaction*& aTrans) |
|
1454 { |
|
1455 // Utility function to create a TIicBusTransaction object from the parameters passed by the user-side TUsideTracnDesc object |
|
1456 |
|
1457 TInt r = KErrNone; |
|
1458 TUsideTracnDesc usTrans; |
|
1459 r=Kern::ThreadRawRead(iClient,aUsideTrancnDesc,&usTrans,sizeof(TUsideTracnDesc)); |
|
1460 if(r!=KErrNone) |
|
1461 { |
|
1462 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans\n")); |
|
1463 return KErrGeneral; // Can't proceed if can't access request parameters |
|
1464 } |
|
1465 // Ensure pointers potentially used for allocation are NULL, to facilitate cleanup |
|
1466 iSpiBuf=NULL; |
|
1467 iI2cBuf=NULL; |
|
1468 iTfer=NULL; |
|
1469 iTransPreamble=NULL; |
|
1470 iFdTfer=NULL; |
|
1471 |
|
1472 // Get the header (depends on the bus type) |
|
1473 TBusType busType = usTrans.iType; |
|
1474 TConfigSpiBufV01 *spiBuf = NULL; |
|
1475 TConfigI2cBufV01 *i2cBuf = NULL; |
|
1476 // extractInfo is used to keep the bufPtr and tfer of the transaction, |
|
1477 // and will later be stored in iExtractInfoArray, sorting by transaction. |
|
1478 // The extractInfo object will be freed in CleanupExtractTrans. |
|
1479 TExtractInfo *extractInfo = new TExtractInfo(); |
|
1480 TDes8* bufPtr=NULL; |
|
1481 if(busType == ESpi) |
|
1482 { |
|
1483 if((spiBuf = new TConfigSpiBufV01()) == NULL) |
|
1484 { |
|
1485 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unable to allocate spiBuf\n")); |
|
1486 return KErrNoMemory; |
|
1487 } |
|
1488 if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *spiBuf, 0, KChunkShiftBy0 ))!=KErrNone) |
|
1489 { |
|
1490 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans.iHeader to spiBuf\n")); |
|
1491 return KErrGeneral; |
|
1492 } |
|
1493 bufPtr=(TDes8*)spiBuf; |
|
1494 } |
|
1495 else if(busType == EI2c) |
|
1496 { |
|
1497 if((i2cBuf = new TConfigI2cBufV01()) == NULL) |
|
1498 { |
|
1499 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unable to allocate i2cBuf\n")); |
|
1500 return KErrNoMemory; |
|
1501 } |
|
1502 if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *i2cBuf, 0, KChunkShiftBy0 ))!=KErrNone) |
|
1503 { |
|
1504 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read usTrans.iHeader to i2cBuf\n")); |
|
1505 return KErrGeneral; |
|
1506 } |
|
1507 bufPtr=(TDes8*)i2cBuf; |
|
1508 } |
|
1509 else |
|
1510 { |
|
1511 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - unrecognised bus type\n")); |
|
1512 return KErrGeneral; |
|
1513 } |
|
1514 extractInfo->iBufPtr = bufPtr; |
|
1515 // Get the half-duplex transfer information |
|
1516 TUsideTferDesc* usTferPtr = usTrans.iHalfDuplexTrans; |
|
1517 TUsideTferDesc usTfer; |
|
1518 r=Kern::ThreadRawRead(iClient,usTferPtr,&usTfer,sizeof(TUsideTferDesc)); |
|
1519 if(r!=KErrNone) |
|
1520 { |
|
1521 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read half-duplex usTfer\n")); |
|
1522 return KErrGeneral; // Can't proceed if can't access request parameters |
|
1523 } |
|
1524 // Need to access the descriptor holding the information to be transferred |
|
1525 TBuf8 <MAX_TRANS_LENGTH> tferData; |
|
1526 r=Kern::ThreadDesRead(iClient,usTfer.iBuffer,tferData,0,KChunkShiftBy0); |
|
1527 if(r!=KErrNone) |
|
1528 { |
|
1529 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read half-duplex tferData\n")); |
|
1530 return KErrGeneral; // Can't proceed if can't access request parameters |
|
1531 } |
|
1532 |
|
1533 TIicBusTransfer::TReqType type=(usTfer.iType == EMasterWrite)?TIicBusTransfer::EMasterWrite:TIicBusTransfer::EMasterRead; |
|
1534 tfer7 = new TIicBusTransfer(type, usTfer.iBufGranularity, &tferData); |
|
1535 extractInfo->iTfer = tfer7; |
|
1536 // Construct the appropriate transaction object with the half-duplex information |
|
1537 TUint8 transFlags = usTrans.iFlags; |
|
1538 |
|
1539 if((transFlags&KTransactionWithPreamble)&&(transFlags&KTransactionWithMultiTransc)) |
|
1540 { |
|
1541 if(usTrans.iPreambleArg == NULL) |
|
1542 { |
|
1543 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - ExtTrans TRequestStatus==NULL\n")); |
|
1544 return KErrArgument; |
|
1545 } |
|
1546 if(usTrans.iMultiTranscArg == NULL) |
|
1547 { |
|
1548 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - ExtTrans TRequestStatus==NULL\n")); |
|
1549 return KErrArgument; |
|
1550 } |
|
1551 iPreambleStatus = (TRequestStatus*)(usTrans.iPreambleArg); |
|
1552 iMultiTranscStatus = (TRequestStatus*)(usTrans.iMultiTranscArg); |
|
1553 TIicBusTransactionPreambleExt* transExt; |
|
1554 |
|
1555 transExt = new TIicBusTransactionPreambleExt(bufPtr, tfer7, (TIicBusPreamble)(&PreambleCallbackFunc), this, |
|
1556 (TIicBusMultiTranscCbFn)(&MultiTranscCallbackFunc), this); |
|
1557 if(transExt == NULL) |
|
1558 { |
|
1559 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n")); |
|
1560 return KErrNoMemory; // Can't proceed if can't access request parameters |
|
1561 } |
|
1562 aTrans = transExt; |
|
1563 |
|
1564 } |
|
1565 else if(transFlags & KTransactionWithPreamble) |
|
1566 { |
|
1567 // Preamble required - construct the derived-class transaction object |
|
1568 if(usTrans.iPreambleArg == NULL) |
|
1569 { |
|
1570 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - preamble TRequestStatus==NULL\n")); |
|
1571 return KErrArgument; |
|
1572 } |
|
1573 iPreambleStatus = (TRequestStatus*)(usTrans.iPreambleArg); |
|
1574 TIicBusTransactionPreamble* TransPreamble; |
|
1575 TransPreamble = new TIicBusTransactionPreamble(bufPtr, tfer7, (TIicBusPreamble)(&PreambleCallbackFunc), this); |
|
1576 if(TransPreamble == NULL) |
|
1577 { |
|
1578 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n")); |
|
1579 return KErrNoMemory; // Can't proceed if can't access request parameters |
|
1580 } |
|
1581 aTrans = TransPreamble; |
|
1582 } |
|
1583 else if(transFlags & KTransactionWithMultiTransc) |
|
1584 { |
|
1585 // Preamble required - construct the derived-class transaction object |
|
1586 if(usTrans.iMultiTranscArg == NULL) |
|
1587 { |
|
1588 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Multi Transc TRequestStatus==NULL\n")); |
|
1589 return KErrArgument; |
|
1590 } |
|
1591 iMultiTranscStatus = (TRequestStatus*)(usTrans.iMultiTranscArg); |
|
1592 TIicBusTransactionMultiTransc* transMultiTransc; |
|
1593 transMultiTransc = new TIicBusTransactionMultiTransc(bufPtr, tfer7, (TIicBusMultiTranscCbFn)(&MultiTranscCallbackFunc), this); |
|
1594 if(transMultiTransc == NULL) |
|
1595 { |
|
1596 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n")); |
|
1597 return KErrNoMemory; // Can't proceed if can't access request parameters |
|
1598 } |
|
1599 aTrans = transMultiTransc; |
|
1600 } |
|
1601 else |
|
1602 { |
|
1603 // Preamble not required |
|
1604 aTrans = new TIicBusTransaction(bufPtr, tfer7); |
|
1605 if(aTrans == NULL) |
|
1606 { |
|
1607 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't create trans\n")); |
|
1608 return KErrNoMemory; // Can't proceed if can't access request parameters |
|
1609 } |
|
1610 } |
|
1611 |
|
1612 // If full duplex transaction is required get that information, too |
|
1613 usTferPtr = usTrans.iFullDuplexTrans; |
|
1614 if(usTferPtr!=NULL) |
|
1615 { |
|
1616 r=Kern::ThreadRawRead(iClient,usTferPtr,&usTfer,sizeof(TUsideTferDesc)); |
|
1617 if(r!=KErrNone) |
|
1618 { |
|
1619 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read full-duplex usTfer\n")); |
|
1620 return KErrGeneral; // Can't proceed if can't access request parameters |
|
1621 } |
|
1622 // Need to access the descriptor holding the information to be transferred |
|
1623 TBuf8 <MAX_TRANS_LENGTH> fdTferData; |
|
1624 r=Kern::ThreadDesRead(iClient,usTfer.iBuffer,fdTferData,0,KChunkShiftBy0); |
|
1625 if(r!=KErrNone) |
|
1626 { |
|
1627 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - Can't read full-duplex tferData\n")); |
|
1628 return KErrGeneral; // Can't proceed if can't access request parameters |
|
1629 } |
|
1630 |
|
1631 type=(usTfer.iType == EMasterWrite)?TIicBusTransfer::EMasterWrite:TIicBusTransfer::EMasterRead; |
|
1632 r=aTrans->SetFullDuplexTrans(iFdTfer); |
|
1633 if(r!=KErrNone) |
|
1634 { |
|
1635 CLIENT_PRINT(("DChannelIicClient::ExtractTransData ERROR - SetFullDuplexTrans returned %d\n",r)); |
|
1636 return r; |
|
1637 } |
|
1638 } |
|
1639 extractInfo->iTrans = aTrans; |
|
1640 iExtractInfoArray.InsertInOrder(extractInfo, ExtractInfoOrderByTrans); |
|
1641 return r; |
|
1642 } |
|
1643 |
|
1644 #define KMaxTferTextLength 20 |
|
1645 #define KLongNodeTestLength 15 |
|
1646 #define KShortNodeTestLength 5 |
|
1647 _LIT(KFullTracnHdrText,"Full duplex test"); // length = 22 |
|
1648 #define KFullTracnHdrTextLength 16 |
|
1649 |
|
1650 |
|
1651 // Create transfer list with three nodes |
|
1652 // All memories are allocated from the kernel heap and referenced by class members |
|
1653 // DeleteFullDuplexTest should be called to release memory after use. |
|
1654 // List created here will be assigned to iHalfDuplexTrans in TIicBusTransaction |
|
1655 // If aNodeLength3 = 0, only return a 2 nodes transfer |
|
1656 TInt DChannelIicClient::CreateTransferListHalfDuplex( |
|
1657 TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1, |
|
1658 TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2, |
|
1659 TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3) |
|
1660 { |
|
1661 buf1 = HBuf8::New(KMaxTferTextLength); |
|
1662 buf2 = HBuf8::New(KMaxTferTextLength); |
|
1663 buf3 = HBuf8::New(KMaxTferTextLength); |
|
1664 tfer1 = new TIicBusTransfer(aNodeDir1,8,buf1); |
|
1665 tfer2 = new TIicBusTransfer(aNodeDir2,8,buf2); |
|
1666 tfer3 = new TIicBusTransfer(aNodeDir3,8,buf3); |
|
1667 |
|
1668 if(buf1 == NULL||buf2 == NULL||buf3 == NULL|| |
|
1669 tfer1 == NULL||tfer2 == NULL||tfer3 == NULL) |
|
1670 { |
|
1671 delete buf1; delete buf2; delete buf3; |
|
1672 delete tfer1; delete tfer2; delete tfer3; |
|
1673 return KErrNoMemory; |
|
1674 } |
|
1675 |
|
1676 TInt i; |
|
1677 for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength1); i++) buf1->Append('*'); |
|
1678 for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength2); i++) buf2->Append('*'); |
|
1679 for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength3); i++) buf3->Append('*'); |
|
1680 |
|
1681 tfer1->LinkAfter(tfer2); |
|
1682 |
|
1683 //allow two nodes |
|
1684 if(aNodeLength3>0) |
|
1685 { |
|
1686 tfer2->LinkAfter(tfer3); |
|
1687 } |
|
1688 |
|
1689 return KErrNone; |
|
1690 |
|
1691 } |
|
1692 |
|
1693 // Create transfer list with three nodes |
|
1694 // All memories are allocated from the kernel heap and referenced by class members |
|
1695 // DeleteFullDuplexTest should be called to release memory after use. |
|
1696 // List created here will be assigned to iFullDuplexTrans in TIicBusTransaction |
|
1697 // If aNodeLength3 = 0, only return a 2 nodes transfer |
|
1698 TInt DChannelIicClient::CreateTransferListFullDuplex( |
|
1699 TIicBusTransfer::TReqType aNodeDir1, TInt aNodeLength1, |
|
1700 TIicBusTransfer::TReqType aNodeDir2, TInt aNodeLength2, |
|
1701 TIicBusTransfer::TReqType aNodeDir3, TInt aNodeLength3) |
|
1702 { |
|
1703 buf4 = HBuf8::New(KMaxTferTextLength); |
|
1704 buf5 = HBuf8::New(KMaxTferTextLength); |
|
1705 buf6 = HBuf8::New(KMaxTferTextLength); |
|
1706 tfer4 = new TIicBusTransfer(aNodeDir1,8,buf4); |
|
1707 tfer5 = new TIicBusTransfer(aNodeDir2,8,buf5); |
|
1708 tfer6 = new TIicBusTransfer(aNodeDir3,8,buf6); |
|
1709 |
|
1710 if(buf4 == NULL||buf5 == NULL||buf6 == NULL|| |
|
1711 tfer4 == NULL||tfer5 == NULL||tfer6 == NULL) |
|
1712 { |
|
1713 delete buf4; delete buf5; delete buf6; |
|
1714 delete tfer4; delete tfer5; delete tfer6; |
|
1715 return KErrNoMemory; |
|
1716 } |
|
1717 |
|
1718 TInt i; |
|
1719 for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength1); i++) buf4->Append('*'); |
|
1720 for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength2); i++) buf5->Append('*'); |
|
1721 for(i=0; (i<KMaxTferTextLength)&&(i<aNodeLength3); i++) buf6->Append('*'); |
|
1722 |
|
1723 tfer4->LinkAfter(tfer5); |
|
1724 |
|
1725 //allow two nodes |
|
1726 if(aNodeLength3>0) |
|
1727 { |
|
1728 tfer5->LinkAfter(tfer6); |
|
1729 } |
|
1730 |
|
1731 return KErrNone; |
|
1732 |
|
1733 } |
|
1734 |
|
1735 // Delete transaction and all allocated transfers and buffers |
|
1736 TInt DChannelIicClient::DeleteFullDuplexTest(TIicBusTransaction *aTrans) |
|
1737 { |
|
1738 delete buf1; delete buf2; delete buf3; |
|
1739 delete tfer1; delete tfer2; delete tfer3; |
|
1740 |
|
1741 delete buf4; delete buf5; delete buf6; |
|
1742 delete tfer4; delete tfer5; delete tfer6; |
|
1743 |
|
1744 delete header; |
|
1745 delete aTrans; |
|
1746 |
|
1747 return KErrNone; |
|
1748 } |
|
1749 |
|
1750 // Do full duplex creation test |
|
1751 TInt DChannelIicClient::DoCreateFullDuplexTransTest(TInt aTestType) |
|
1752 { |
|
1753 CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest starts\n")); |
|
1754 |
|
1755 TInt r=KErrNone; |
|
1756 switch(aTestType) |
|
1757 { |
|
1758 case RBusDevIicClient::ETestValidFullDuplexTrans: |
|
1759 { |
|
1760 // equal length, opposite transfer direction |
|
1761 r = CreateTransferListHalfDuplex( |
|
1762 TIicBusTransfer::EMasterWrite, KLongNodeTestLength, |
|
1763 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1764 TIicBusTransfer::EMasterWrite, KLongNodeTestLength); |
|
1765 if(r!=KErrNone) break; |
|
1766 r = CreateTransferListFullDuplex( |
|
1767 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1768 TIicBusTransfer::EMasterWrite, KLongNodeTestLength, |
|
1769 TIicBusTransfer::EMasterRead, KLongNodeTestLength); |
|
1770 if(r!=KErrNone) break; |
|
1771 break; |
|
1772 } |
|
1773 case RBusDevIicClient::ETestInvalidFullDuplexTrans1: |
|
1774 { |
|
1775 // equal length, same transfer direction |
|
1776 r = CreateTransferListHalfDuplex( |
|
1777 TIicBusTransfer::EMasterWrite, KLongNodeTestLength, |
|
1778 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1779 TIicBusTransfer::EMasterWrite, KLongNodeTestLength); |
|
1780 if(r!=KErrNone) break; |
|
1781 r = CreateTransferListFullDuplex( |
|
1782 TIicBusTransfer::EMasterWrite, KLongNodeTestLength, |
|
1783 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1784 TIicBusTransfer::EMasterWrite, KLongNodeTestLength); |
|
1785 if(r!=KErrNone) break; |
|
1786 break; |
|
1787 } |
|
1788 case RBusDevIicClient::ETestInvalidFullDuplexTrans2: |
|
1789 { |
|
1790 // different, opposite transfer direction |
|
1791 r = CreateTransferListHalfDuplex( |
|
1792 TIicBusTransfer::EMasterWrite, KShortNodeTestLength, |
|
1793 TIicBusTransfer::EMasterRead, KShortNodeTestLength, |
|
1794 TIicBusTransfer::EMasterWrite, KShortNodeTestLength); |
|
1795 if(r!=KErrNone) break; |
|
1796 r = CreateTransferListFullDuplex( |
|
1797 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1798 TIicBusTransfer::EMasterWrite, KLongNodeTestLength, |
|
1799 TIicBusTransfer::EMasterRead, KLongNodeTestLength); |
|
1800 if(r!=KErrNone) break; |
|
1801 break; |
|
1802 } |
|
1803 case RBusDevIicClient::ETestLastNodeFullDuplexTrans: |
|
1804 { |
|
1805 // different length for the last node |
|
1806 r = CreateTransferListHalfDuplex( |
|
1807 TIicBusTransfer::EMasterWrite, KLongNodeTestLength, |
|
1808 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1809 TIicBusTransfer::EMasterWrite, KShortNodeTestLength); |
|
1810 if(r!=KErrNone) break; |
|
1811 r = CreateTransferListFullDuplex( |
|
1812 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1813 TIicBusTransfer::EMasterWrite, KLongNodeTestLength, |
|
1814 TIicBusTransfer::EMasterRead, KLongNodeTestLength); |
|
1815 if(r!=KErrNone) break; |
|
1816 break; |
|
1817 } |
|
1818 case RBusDevIicClient::ETestDiffNodeNoFullDuplexTrans: |
|
1819 { |
|
1820 // equal length, opposite transfer direction |
|
1821 r = CreateTransferListHalfDuplex( |
|
1822 TIicBusTransfer::EMasterWrite, KLongNodeTestLength, |
|
1823 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1824 TIicBusTransfer::EMasterWrite, KShortNodeTestLength); |
|
1825 if(r!=KErrNone) break; |
|
1826 r = CreateTransferListFullDuplex( |
|
1827 TIicBusTransfer::EMasterRead, KLongNodeTestLength, |
|
1828 TIicBusTransfer::EMasterWrite, KShortNodeTestLength, |
|
1829 TIicBusTransfer::EMasterRead, 0); |
|
1830 if(r!=KErrNone) break; |
|
1831 break; |
|
1832 } |
|
1833 |
|
1834 |
|
1835 default: |
|
1836 break; |
|
1837 } |
|
1838 |
|
1839 header = HBuf8::New(KFullTracnHdrTextLength); |
|
1840 TIicBusTransaction *Trans = new TIicBusTransaction(header,tfer1); |
|
1841 |
|
1842 if((r!=KErrNone) || (header == NULL) || (Trans == NULL)) |
|
1843 { |
|
1844 CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest ERROR - failed to allocate the necessary memory\n")); |
|
1845 DeleteFullDuplexTest(Trans); |
|
1846 return KErrNoMemory; |
|
1847 } |
|
1848 |
|
1849 header->Copy(KFullTracnHdrText); |
|
1850 |
|
1851 TInt TestResult = Trans->SetFullDuplexTrans(tfer4); |
|
1852 |
|
1853 CLIENT_PRINT(("DChannelIicClient::DoCreateFullDuplexTransTest IIC after SetFullDuplexTrans TestResult =%d\n", TestResult)); |
|
1854 |
|
1855 r = DeleteFullDuplexTest(Trans); |
|
1856 |
|
1857 return TestResult; |
|
1858 |
|
1859 } |
|
1860 |
|
1861 |
|
1862 TInt DChannelIicClient::CreateDefaultSpiBuf(TConfigSpiBufV01*& aBuf) |
|
1863 // Utility function to create a buffer for the SPI bus |
|
1864 { |
|
1865 TInt r=CreateSpiBuf(aBuf, ESpiWordWidth_8, 100000, ESpiPolarityLowRisingEdge, 100 ,ELittleEndian, EMsbFirst, 10, ESpiCSPinActiveLow); |
|
1866 return r; |
|
1867 } |
|
1868 |
|
1869 // DoPriorityTest does the following actions: |
|
1870 // 1. switch the bus (only use SPI test PSL) to priority test mode |
|
1871 // 2. create 5 test transactions with different priorities and 1 blocking transaction |
|
1872 // 3. enable blocking in test channel |
|
1873 // we can only block the test channel, we cannot suspend the bus controller |
|
1874 // 3. send blocking transaction to the test channel |
|
1875 // the blocking transaction is just normal transaction. |
|
1876 // the test channel will be blocked once the first transaction is arrived |
|
1877 // 4. send test transactions in opposite order to their priority |
|
1878 // 5. unblock test channel |
|
1879 // 6. read test result from channel |
|
1880 // 7. switch the bus to normal mode |
|
1881 TInt DChannelIicClient::DoPriorityTest(TInt aBusId) |
|
1882 { |
|
1883 TInt TestResult=KErrNone; |
|
1884 // Use the IIC StaticExtension interface to pass the request to the bus implementation |
|
1885 // To support testing, any values of aId for StaticExtension must be shifted left one place |
|
1886 TUint testId = ((TUint)(RBusDevIicClient::ECtlIoPriorityTest))<<1; |
|
1887 TInt r = KErrNone; |
|
1888 |
|
1889 r = StaticExtension(aBusId, testId, NULL, NULL); |
|
1890 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1891 if(r == KErrNone) |
|
1892 { |
|
1893 buf1 = HBuf8::New(1); |
|
1894 buf2 = HBuf8::New(1); |
|
1895 buf3 = HBuf8::New(1); |
|
1896 buf4 = HBuf8::New(1); |
|
1897 buf5 = HBuf8::New(1); |
|
1898 //buffer for blocking transaction |
|
1899 buf6 = HBuf8::New(1); |
|
1900 |
|
1901 if(buf1 == NULL||buf2 == NULL||buf3 == NULL||buf4 == NULL||buf5 == NULL||buf6 == NULL) |
|
1902 { |
|
1903 delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6; |
|
1904 r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL); |
|
1905 return KErrNoMemory; |
|
1906 } |
|
1907 tfer1 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1); |
|
1908 tfer2 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf2); |
|
1909 tfer3 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf3); |
|
1910 tfer4 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf4); |
|
1911 tfer5 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf5); |
|
1912 //transfer for blocking transaction |
|
1913 tfer6 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf6); |
|
1914 |
|
1915 if(tfer1 == NULL||tfer2 == NULL||tfer3 == NULL||tfer4 == NULL||tfer5 == NULL||tfer6 == NULL) |
|
1916 { |
|
1917 delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6; |
|
1918 delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6; |
|
1919 r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL); |
|
1920 return KErrNoMemory; |
|
1921 } |
|
1922 |
|
1923 TConfigSpiBufV01* spiHeader1 = NULL; |
|
1924 TConfigSpiBufV01* spiHeader2 = NULL; |
|
1925 TConfigSpiBufV01* spiHeader3 = NULL; |
|
1926 TConfigSpiBufV01* spiHeader4 = NULL; |
|
1927 TConfigSpiBufV01* spiHeader5 = NULL; |
|
1928 TConfigSpiBufV01* spiHeaderBlock = NULL; //header for blocking transaction |
|
1929 |
|
1930 |
|
1931 TInt r = CreateDefaultSpiBuf(spiHeader1); |
|
1932 if(r == KErrNone) r = CreateDefaultSpiBuf(spiHeader2); |
|
1933 if(r == KErrNone) r = CreateDefaultSpiBuf(spiHeader3); |
|
1934 if(r == KErrNone) r = CreateDefaultSpiBuf(spiHeader4); |
|
1935 if(r == KErrNone) r = CreateDefaultSpiBuf(spiHeader5); |
|
1936 //header for blocking transaction |
|
1937 if(r == KErrNone) r = CreateDefaultSpiBuf(spiHeaderBlock); |
|
1938 |
|
1939 if(r != KErrNone||spiHeader1 == NULL||spiHeader2 == NULL||spiHeader3 == NULL||spiHeader4 == NULL||spiHeader5 == NULL||spiHeaderBlock == NULL) |
|
1940 { |
|
1941 delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6; |
|
1942 delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6; |
|
1943 delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock; |
|
1944 r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL); |
|
1945 return KErrNoMemory; |
|
1946 } |
|
1947 |
|
1948 TIicBusTransaction* Transc1; Transc1 = new TIicBusTransaction(spiHeader1,tfer1, KPriorityTestPrio[0]); |
|
1949 TIicBusTransaction* Transc2; Transc2 = new TIicBusTransaction(spiHeader2,tfer2, KPriorityTestPrio[1]); |
|
1950 TIicBusTransaction* Transc3; Transc3 = new TIicBusTransaction(spiHeader3,tfer3, KPriorityTestPrio[2]); |
|
1951 TIicBusTransaction* Transc4; Transc4 = new TIicBusTransaction(spiHeader4,tfer4, KPriorityTestPrio[3]); |
|
1952 TIicBusTransaction* Transc5; Transc5 = new TIicBusTransaction(spiHeader5,tfer5, KPriorityTestPrio[4]); |
|
1953 //blocking transaction |
|
1954 TIicBusTransaction* TranscBlock; TranscBlock = new TIicBusTransaction(spiHeaderBlock,tfer6, KPriorityTestPrio[5]); |
|
1955 |
|
1956 if(Transc1 == NULL||Transc2 == NULL||Transc3 == NULL||Transc4 == NULL||Transc5 == NULL||TranscBlock == NULL) |
|
1957 { |
|
1958 delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6; |
|
1959 delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6; |
|
1960 delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock; |
|
1961 delete Transc1; delete Transc2; delete Transc3; delete Transc4; delete Transc5; delete TranscBlock; |
|
1962 r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL); |
|
1963 return KErrNoMemory; |
|
1964 } |
|
1965 |
|
1966 //dummy call back func is provided for asyn call |
|
1967 TIicBusCallback* cb = new TIicBusCallback(DummyCallbackFunc, this, iDfcQue, 5); // 5 arbitrary |
|
1968 |
|
1969 // block the device channel. the channel will not be blocked until the first transaction arrive the channel |
|
1970 // To support testing, any values of aId for StaticExtension must be shifted left one place |
|
1971 TUint testId=((TUint)RBusDevIicClient::ECtlIoBlockReqCompletion)<<1; |
|
1972 r = StaticExtension(aBusId, testId, NULL, NULL); |
|
1973 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1974 |
|
1975 r = QueueTransaction(aBusId, TranscBlock, cb); //send TranscBlock to block the channel |
|
1976 // send ordered transactions |
|
1977 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1978 |
|
1979 r = QueueTransaction(aBusId, Transc1, cb); |
|
1980 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1981 r = QueueTransaction(aBusId, Transc2, cb); |
|
1982 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1983 r = QueueTransaction(aBusId, Transc3, cb); |
|
1984 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1985 r = QueueTransaction(aBusId, Transc4, cb); |
|
1986 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1987 r = QueueTransaction(aBusId, Transc5, cb); |
|
1988 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1989 |
|
1990 // unblock device channel |
|
1991 testId=((TUint)RBusDevIicClient::ECtlIoUnblockReqCompletion)<<1; |
|
1992 r = StaticExtension(aBusId, testId, NULL, NULL); |
|
1993 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
1994 |
|
1995 #define KPriorityTestGetResultRetry 3 |
|
1996 for(TInt i=0; i<KPriorityTestGetResultRetry ; i++) |
|
1997 { |
|
1998 NKern::Sleep(500); |
|
1999 testId=((TUint)RBusDevIicClient::EGetTestResult)<<1; |
|
2000 TestResult = StaticExtension(aBusId, testId, NULL, NULL); |
|
2001 if(TestResult!=KErrNotReady) break; |
|
2002 } |
|
2003 |
|
2004 cb->Cancel(); |
|
2005 delete cb; |
|
2006 delete buf1; delete buf2; delete buf3; delete buf4; delete buf5; delete buf6; |
|
2007 delete tfer1; delete tfer2; delete tfer3; delete tfer4; delete tfer5; delete tfer6; |
|
2008 delete spiHeader1; delete spiHeader2; delete spiHeader3; delete spiHeader4; delete spiHeader5; delete spiHeaderBlock; |
|
2009 delete Transc1; delete Transc2; delete Transc3; delete Transc4; delete Transc5; delete TranscBlock; |
|
2010 |
|
2011 } |
|
2012 r = StaticExtension(aBusId, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL); |
|
2013 return TestResult; |
|
2014 } |
|
2015 |
|
2016 TInt DChannelIicClient::ConstructTransactionOne(TIicBusTransaction*& aTrans) |
|
2017 { |
|
2018 // Transaction is to contain three transfers, with data defined by |
|
2019 // KTransOneTferOne[], KTransOneTferTwo[], KTransOneTferThree[] |
|
2020 buf1 = HBuf8::New(21); |
|
2021 buf2 = HBuf8::New(8); |
|
2022 buf3 = HBuf8::New(6); |
|
2023 tfer1 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1); |
|
2024 tfer2 = new TIicBusTransfer(TIicBusTransfer::EMasterRead,8,buf2); |
|
2025 tfer3 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf3); |
|
2026 TInt r = CreateDefaultSpiBuf(spiHeader); |
|
2027 if((r != KErrNone)||(spiHeader == NULL)||(buf1 == NULL)||(buf2 == NULL)||(buf3 == NULL)||(tfer1 == NULL)||(tfer2 == NULL)||(tfer3 == NULL)) |
|
2028 { |
|
2029 CLIENT_PRINT(("DChannelIicClient::ConstructTransactionOne ERROR - failed to allocate the necessary memory\n")); |
|
2030 delete buf1; |
|
2031 delete buf2; |
|
2032 delete buf3; |
|
2033 delete tfer1; |
|
2034 delete tfer2; |
|
2035 delete tfer3; |
|
2036 delete spiHeader; |
|
2037 delete aTrans; |
|
2038 return KErrNoMemory; |
|
2039 } |
|
2040 aTrans = new TIicBusTransaction(spiHeader,tfer1); |
|
2041 buf1->Copy(&(KTransOneTferOne[0]),21); |
|
2042 buf2->Copy(&(KTransOneTferTwo[0]),8); |
|
2043 buf3->Copy(&(KTransOneTferThree[0]),6); |
|
2044 tfer1->LinkAfter(tfer2); |
|
2045 tfer2->LinkAfter(tfer3); |
|
2046 return KErrNone; |
|
2047 } |
|
2048 |
|
2049 void DChannelIicClient::CleanupTransactionOne(TIicBusTransaction*& aTrans) |
|
2050 { |
|
2051 // Release the allocated memory |
|
2052 delete buf1; |
|
2053 buf1=NULL; |
|
2054 delete buf2; |
|
2055 buf2=NULL; |
|
2056 delete buf3; |
|
2057 buf3=NULL; |
|
2058 delete tfer1; |
|
2059 tfer1=NULL; |
|
2060 delete tfer2; |
|
2061 tfer2=NULL; |
|
2062 delete tfer3; |
|
2063 tfer3=NULL; |
|
2064 delete spiHeader; |
|
2065 spiHeader=NULL; |
|
2066 delete aTrans; |
|
2067 aTrans=NULL; |
|
2068 } |
|
2069 |
|
2070 |
|
2071 void DChannelIicClient::CleanupTransaction(TIicBusTransaction*& aTrans) |
|
2072 { |
|
2073 delete iSpiBuf; |
|
2074 iSpiBuf=NULL; |
|
2075 delete iI2cBuf; |
|
2076 iI2cBuf=NULL; |
|
2077 TIicBusTransfer* currTfer = iTfer; |
|
2078 TIicBusTransfer* nextTfer = NULL; |
|
2079 while(currTfer) |
|
2080 { |
|
2081 TIicBusTransfer* nextTfer = (TIicBusTransfer*)(currTfer->Next()); |
|
2082 delete currTfer; |
|
2083 if(nextTfer) |
|
2084 currTfer = nextTfer; |
|
2085 else |
|
2086 currTfer = NULL; |
|
2087 }; |
|
2088 iTfer=NULL; |
|
2089 currTfer = iFdTfer; |
|
2090 nextTfer = NULL; |
|
2091 while(currTfer) |
|
2092 { |
|
2093 TIicBusTransfer* nextTfer = (TIicBusTransfer*)(currTfer->Next()); |
|
2094 delete currTfer; |
|
2095 if(nextTfer) |
|
2096 currTfer = nextTfer; |
|
2097 else |
|
2098 currTfer = NULL; |
|
2099 }; |
|
2100 iFdTfer=NULL; |
|
2101 if(aTrans!=NULL) |
|
2102 { |
|
2103 delete aTrans; |
|
2104 aTrans=NULL; |
|
2105 } |
|
2106 if(iTransPreamble!=NULL) |
|
2107 { |
|
2108 delete iTransPreamble; |
|
2109 iTransPreamble=NULL; |
|
2110 } |
|
2111 } |
|
2112 |
|
2113 void DChannelIicClient::TransModifCallback(TIicBusTransaction* /*aTrans*/, TInt /*aBusId*/, TInt aResult, TAny* aParam) |
|
2114 { |
|
2115 // Callback function used to test re-use of transaction and transfer buffers |
|
2116 // aParam is the address of the simulated client driver |
|
2117 DChannelIicClient* channel = (DChannelIicClient*)aParam; |
|
2118 TTransBufReuseData* reuseData = &(channel->iTransBufReuseData); |
|
2119 |
|
2120 // Since the transaction is no longer queued, should be able to modify the transfer and transaction content |
|
2121 channel->TestTransModification(reuseData->iTransaction, reuseData->iHdTfer, reuseData->iFdTfer, reuseData->iHdr); |
|
2122 |
|
2123 // Complete the user's request, delete objects allocated for this test and return |
|
2124 Kern::RequestComplete(channel->iClient, channel->iStatus, aResult); |
|
2125 delete reuseData->iCallback; // Must do this before deleting the Transaction, in CleanupTransaction |
|
2126 channel->CleanupTransaction(channel->iTrans); |
|
2127 return; |
|
2128 } |
|
2129 |
|
2130 |
|
2131 void DChannelIicClient::TestTransModification(TIicBusTransaction* aTransaction, |
|
2132 TIicBusTransfer* aHdTfer, |
|
2133 TIicBusTransfer* aFdTfer, |
|
2134 TDes8* aHdr) |
|
2135 { |
|
2136 // Function to test that the content of Transaction and Transfer objects can be modified |
|
2137 // This assumes that the Transaction is in the appropriate state (EFree) - otherwise, the code will assert |
|
2138 // This function also assumes that transaction has aleady added the half-duplex and full-duplex transfers |
|
2139 // that are passed in as arguments, and that the transfers lists are non-NULL |
|
2140 // The original type of the transfers (read, write) are ignored, since it is not of interest in this test - |
|
2141 // instead, what is important is to ensure that the half-duplex and full-duplex transfer types are in opposing |
|
2142 // directions - so the types are explicitly set in this test. |
|
2143 // |
|
2144 TDes8* origBuf = NULL; |
|
2145 TInt8 origGranularity = 0; |
|
2146 |
|
2147 // Create a buffer for use in this function |
|
2148 _LIT(temporaryText,"Temporary Text"); |
|
2149 TBuf8<15> tempBuf_8; |
|
2150 tempBuf_8.Copy(temporaryText); |
|
2151 |
|
2152 // Test modification of the two transfer lists while still part of the transaction |
|
2153 origBuf = (TDes8*)(aHdTfer->GetBuffer()); |
|
2154 origGranularity = aHdTfer->WordWidth(); |
|
2155 aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8); |
|
2156 aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf); |
|
2157 |
|
2158 origBuf = (TDes8*)(aFdTfer->GetBuffer()); |
|
2159 origGranularity = aFdTfer->WordWidth(); |
|
2160 aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8); |
|
2161 aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf); |
|
2162 |
|
2163 // Test transfers can be removed from the transaction |
|
2164 aTransaction->RemoveHalfDuplexTrans(); |
|
2165 aTransaction->RemoveFullDuplexTrans(); |
|
2166 |
|
2167 // Test modification of the two transfer lists while not part of a transaction |
|
2168 origBuf = (TDes8*)(aHdTfer->GetBuffer()); |
|
2169 origGranularity = aHdTfer->WordWidth(); |
|
2170 aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8); |
|
2171 aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf); |
|
2172 |
|
2173 origBuf = (TDes8*)(aFdTfer->GetBuffer()); |
|
2174 origGranularity = aFdTfer->WordWidth(); |
|
2175 aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8); |
|
2176 aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf); |
|
2177 |
|
2178 // Test transfers can be re-added to the transaction |
|
2179 aTransaction->SetHalfDuplexTrans(aHdr,aHdTfer); |
|
2180 aTransaction->SetFullDuplexTrans(aFdTfer); |
|
2181 |
|
2182 // Test modification of the two transfer lists now re-added to the transaction |
|
2183 origBuf = (TDes8*)(aHdTfer->GetBuffer()); |
|
2184 origGranularity = aHdTfer->WordWidth(); |
|
2185 aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, &tempBuf_8); |
|
2186 aHdTfer->SetTransferData(TIicBusTransfer::EMasterRead, origGranularity, origBuf); |
|
2187 |
|
2188 origBuf = (TDes8*)(aFdTfer->GetBuffer()); |
|
2189 origGranularity = aFdTfer->WordWidth(); |
|
2190 aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, &tempBuf_8); |
|
2191 aFdTfer->SetTransferData(TIicBusTransfer::EMasterWrite, origGranularity, origBuf); |
|
2192 |
|
2193 return; |
|
2194 } |
|
2195 |
|
2196 TInt DChannelIicClient::DoControl(TInt aId, TAny* a1, TAny* a2) |
|
2197 { |
|
2198 CLIENT_PRINT(("DChannelIicClient::DoControl invoked with aId=0x%x, a1=0x%x, a2=0x%x\n", aId,a1,a2)); |
|
2199 TInt r=KErrNone; |
|
2200 // To support testing, any values of aId for StaticExtension must be shifted left one place |
|
2201 // and for a Slave tests, the two msbs must be zero |
|
2202 TInt ctrlIoVal = 0; |
|
2203 if((aId & KTestMasterControlIo) == KTestMasterControlIo) |
|
2204 ctrlIoVal = (aId << 1); |
|
2205 if((aId & KTestSlaveControlIo) == KTestSlaveControlIo) |
|
2206 ctrlIoVal = (aId << 1) & 0x3FFFFFFF; |
|
2207 switch(aId) |
|
2208 { |
|
2209 case(RBusDevIicClient::EQTransSync): |
|
2210 { |
|
2211 // a1 specifies Bus Realisation Config to use |
|
2212 // a2 is a pointer to TUsideTracnDesc |
|
2213 TIicBusTransaction* trans = NULL; |
|
2214 TIicBusTransfer* tfer = NULL; |
|
2215 TConfigSpiBufV01 *spiBuf = NULL; |
|
2216 |
|
2217 //Read the transaction header to determin if it is a multi-transaction type |
|
2218 TUsideTracnDesc usTrans; |
|
2219 |
|
2220 if((Kern::ThreadRawRead(iClient,a2,&usTrans,sizeof(TUsideTracnDesc)))!=KErrNone) |
|
2221 { |
|
2222 CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - Can't read iHeader to spiBuf\n")); |
|
2223 return KErrGeneral; |
|
2224 } |
|
2225 |
|
2226 if((usTrans.iFlags)&KTransactionWithMultiTransc) |
|
2227 { |
|
2228 // Since we are testing a multi-transaction, create another transaction object iMultiTransac, |
|
2229 // to represent the delayed part of the multi-transaction. After the preliminary |
|
2230 // transaction(passed from t_iic, with one read transfer) has been performed, |
|
2231 // the IIC code will find that it is part of a |
|
2232 // multi-transaction; it will call the callback for the transaction(set as MultiTranscCallbackFunc, |
|
2233 // in ExtractTransData) and this will return a pointer to the next part of the multi-transaction |
|
2234 // to be performed(iMultiTransac). It will then immediately pass this transaction object |
|
2235 // to the PSL for processing - before considering any other transactions that have been |
|
2236 // requested, and without completing the multi-transaction request(this is done once |
|
2237 // iMultiTransac has been processed) |
|
2238 buf1 = HBuf8::New(1); |
|
2239 spiBuf = new TConfigSpiBufV01(); |
|
2240 if(buf1 == NULL||spiBuf == NULL) {delete buf1;delete spiBuf; return KErrNoMemory;} |
|
2241 |
|
2242 |
|
2243 if((r=Kern::ThreadDesRead(iClient, usTrans.iHeader, *spiBuf, 0, KChunkShiftBy0 ))!=KErrNone) |
|
2244 { |
|
2245 CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - Can't read iHeader to spiBuf\n")); |
|
2246 return KErrGeneral; |
|
2247 } |
|
2248 |
|
2249 tfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1); |
|
2250 if(tfer == NULL) {delete buf1; delete spiBuf; return KErrNoMemory;} |
|
2251 |
|
2252 iMultiTransac = new TIicBusTransaction((TDes8*)spiBuf, tfer); |
|
2253 if(iMultiTransac == NULL) {delete buf1; delete spiBuf; delete tfer; return KErrNoMemory;} |
|
2254 } |
|
2255 r = ExtractTransData((TUsideTracnDesc*)a2, trans); |
|
2256 if(r!=KErrNone) |
|
2257 { |
|
2258 CLIENT_PRINT(("DChannelIicClient::DoControl ERROR - ExtractTransData returned %d\n",r)); |
|
2259 return r; |
|
2260 } |
|
2261 CLIENT_PRINT(("DChannelIicClient::DoControl invoking (synchronous) QueueTransaction with busId=0x%x, trans=0x%x\n",(TUint32)a1,trans)); |
|
2262 |
|
2263 r = QueueTransaction((TUint32)a1, trans); |
|
2264 CleanupExtractTrans(trans); |
|
2265 CleanupTransaction(trans); |
|
2266 if((usTrans.iFlags)&KTransactionWithMultiTransc) |
|
2267 { |
|
2268 delete buf1; |
|
2269 delete spiBuf; |
|
2270 delete tfer; |
|
2271 delete iMultiTransac; |
|
2272 } |
|
2273 break; |
|
2274 } |
|
2275 case(RBusDevIicClient::ECtlIoBlockReqCompletion): |
|
2276 case(RBusDevIicClient::ECtlIoUnblockReqCompletion): |
|
2277 case(RBusDevIicClient::ECtlIoDeRegChan): |
|
2278 { |
|
2279 // a1 specifies Bus Realisation Config to use |
|
2280 CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1)); |
|
2281 // Use the IIC StaticExtension interface to pass the request to the bus implementation |
|
2282 r = StaticExtension((TUint32)a1, (TUint)ctrlIoVal, NULL, NULL); |
|
2283 break; |
|
2284 } |
|
2285 case(RBusDevIicClient::ECtlIoTestFullDuplexTrans): |
|
2286 { |
|
2287 // a1 specifies Bus Realisation Config to use |
|
2288 CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1)); |
|
2289 r = DoCreateFullDuplexTransTest((TInt)a2); |
|
2290 break; |
|
2291 } |
|
2292 case(RBusDevIicClient::ECtlIoPriorityTest): |
|
2293 { |
|
2294 // a1 specifies Bus Realisation Config to use |
|
2295 CLIENT_PRINT(("DChannelIicClient::DoControl invoking StaticExtension with aId=%d, busId=0x%x\n",aId,(TUint32)a1)); |
|
2296 r = DoPriorityTest((TUint32)a1); |
|
2297 break; |
|
2298 } |
|
2299 |
|
2300 case(RBusDevIicClient::ECtlIoTracnOne): |
|
2301 { |
|
2302 // a1 specifies Bus Realisation Config to use |
|
2303 CLIENT_PRINT(("DChannelIicClient::StaticExtension invoking StaticExtension with ctrlIoVal=%d, busId=0x%x\n",aId,(TUint32)a1)); |
|
2304 // Use the IIC StaticExtension interface to pass the request to the bus implementation |
|
2305 r = StaticExtension((TUint32)a1, (TUint)ctrlIoVal, NULL, NULL); |
|
2306 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("StaticExtension",__LINE__)); |
|
2307 if(r == KErrNone) |
|
2308 { |
|
2309 // Create then send (synchronously) Transaction One |
|
2310 r = ConstructTransactionOne(iTrans); |
|
2311 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
2312 r = QueueTransaction((TUint32)a1, iTrans); |
|
2313 __ASSERT_ALWAYS(r == KErrNone,Kern::Fault("DoControl",__LINE__)); |
|
2314 CleanupTransactionOne(iTrans); |
|
2315 } |
|
2316 r = StaticExtension((TUint32)a1, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL); |
|
2317 break; |
|
2318 } |
|
2319 case(RBusDevIicClient::ECtlIoSetTimeOutFlag): |
|
2320 { |
|
2321 CLIENT_PRINT(("DChannelIicClient::DoControl instruct the bus that it is to simulate a slave timeout")); |
|
2322 // To support testing, function index passed to StaticExtension must be shifted one place to the left |
|
2323 TUint testIndex = ((TUint)RBusDevIicClient::ECtlIoSetTimeOutFlag)<<1;; |
|
2324 r = StaticExtension((TUint32)a1, testIndex, NULL, NULL); |
|
2325 break; |
|
2326 } |
|
2327 case(RBusDevIicClient::ECtlIoNone): |
|
2328 { |
|
2329 CLIENT_PRINT(("DChannelIicClient::DoControl Return the bus to its default test state")); |
|
2330 r = StaticExtension((TUint32)a1, (TUint)RBusDevIicClient::ECtlIoNone, NULL, NULL); |
|
2331 break; |
|
2332 } |
|
2333 |
|
2334 // Support for MasterSlave processing |
|
2335 |
|
2336 case(RBusDevIicClient::ECaptureChanSync): |
|
2337 { |
|
2338 // a1 is a pointer to the TDes8* aConfigHdr |
|
2339 // a2 is a pointer to TInt* parms[2], where: |
|
2340 // parms[0]=(TInt*)aBusId; |
|
2341 // parms[1]=&aChannelId; |
|
2342 // |
|
2343 TInt* parms[2]; |
|
2344 r=Kern::ThreadRawRead(iClient,a2,&(parms[0]),2*sizeof(TInt*)); |
|
2345 if(r!=KErrNone) |
|
2346 break; // Can't proceed if can't access request parameters |
|
2347 // |
|
2348 TInt hdrSize = Kern::ThreadGetDesLength(iClient,a1); |
|
2349 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl hdrSize = 0x%x\n",hdrSize)); |
|
2350 if (hdrSize<=0) |
|
2351 { |
|
2352 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl ERROR, hdrSize is invalid\n")); |
|
2353 return KErrArgument; |
|
2354 } |
|
2355 if((iConfigHdr = HBuf8::New(hdrSize)) == NULL) |
|
2356 return KErrNoMemory; |
|
2357 r = Kern::ThreadDesRead(iClient,a1,*iConfigHdr,0); |
|
2358 if(r!=KErrNone) |
|
2359 { |
|
2360 delete iConfigHdr; |
|
2361 return r; |
|
2362 } |
|
2363 // Store the address of the user-side variable to update with the ChannelId |
|
2364 iClientChanId=parms[1]; |
|
2365 |
|
2366 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking (synchronous) CaptureChannel\n")); |
|
2367 r = CaptureChannel((TInt)(parms[0]), iConfigHdr, iNotif, iChannelId); |
|
2368 if(r != KErrNone) |
|
2369 delete iConfigHdr; |
|
2370 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl CaptureChannelgave iChannelId=0x%x\n",iChannelId)); |
|
2371 |
|
2372 TInt r=Kern::ThreadRawWrite(iClient,iClientChanId,&iChannelId,sizeof(TInt)); |
|
2373 (void)r; // Silence the compiler |
|
2374 |
|
2375 break; |
|
2376 } |
|
2377 |
|
2378 case(RBusDevIicClient::EReleaseChan): |
|
2379 { |
|
2380 // a1 represents TInt aChannelId |
|
2381 CLIENT_PRINT(("DChannelIicSlaveClient::DoControl invoking ReleaseChannel\n")); |
|
2382 r = ReleaseChannel((TInt)a1); |
|
2383 delete iConfigHdr; |
|
2384 break; |
|
2385 } |
|
2386 |
|
2387 case(RBusDevIicClient::EInitSlaveClient): |
|
2388 { |
|
2389 r=InitSlaveClient(); |
|
2390 break; |
|
2391 } |
|
2392 |
|
2393 #ifdef STANDALONE_CHANNEL |
|
2394 case(RBusDevIicClient::ETestIicChannelInlineFunc): |
|
2395 { |
|
2396 TTestIicChannelInterface channelInterface(DIicBusChannel::EMaster, DIicBusChannel::EI2c, DIicBusChannel::EHalfDuplex); |
|
2397 r = channelInterface.TestInterface(); |
|
2398 break; |
|
2399 } |
|
2400 #endif |
|
2401 |
|
2402 default: |
|
2403 { |
|
2404 CLIENT_PRINT(("DChannelIicClient::DoControl - unrecognised value for aId=0x%x\n",aId)); |
|
2405 r=KErrArgument; |
|
2406 break; |
|
2407 } |
|
2408 } |
|
2409 return r; |
|
2410 } |
|
2411 |
|
2412 TInt DChannelIicClient::DoRequest(TInt aId, TRequestStatus* aStatus, TAny* a1, TAny* a2) |
|
2413 { |
|
2414 CLIENT_PRINT(("DChannelIicClient::DoRequest invoked with aId=0x%x, aStatus=0x%x, a1=0x%x, a2=0x%x\n", aId,aStatus,a1,a2)); |
|
2415 |
|
2416 TInt r=KErrNone; |
|
2417 switch(aId) |
|
2418 { |
|
2419 case(RBusDevIicClient::EQTransAsync): |
|
2420 { |
|
2421 // a1 specifies Bus Realisation Config to use |
|
2422 // a2 is a pointer to TIicBusTransaction |
|
2423 TIicBusTransaction* trans = NULL; |
|
2424 r = ExtractTransData((TUsideTracnDesc*)a2, trans); |
|
2425 if(r!=KErrNone) |
|
2426 { |
|
2427 CLIENT_PRINT(("DChannelIicClient::DoRequest ERROR - ExtractTransData returned %d\n",r)); |
|
2428 return r; |
|
2429 } |
|
2430 // Create TIicBusCallback object |
|
2431 TIicBusCallback* cb = new TIicBusCallback(AsyncCallbackFunc, this, iDfcQue, 5); // 5 arbitrary |
|
2432 TTransCbPair* cbPair = new TTransCbPair(); |
|
2433 cbPair->iCb=cb; |
|
2434 cbPair->iTrans=trans; |
|
2435 // Create an entry in the RPointerArray for TRequestStatus - TIicBusTransaction pairs |
|
2436 TTransStatusPair* pair = new TTransStatusPair(); |
|
2437 pair->iReq=aStatus; |
|
2438 pair->iTrans=trans; |
|
2439 r=InsertPairs(pair,cbPair); |
|
2440 if(r!=KErrNone) |
|
2441 { |
|
2442 CLIENT_PRINT(("DChannelIicClient::DoRequest ERROR - InsertInOrder returned %d\n",r)); |
|
2443 return r; |
|
2444 } |
|
2445 CLIENT_PRINT(("DChannelIicClient::DoRequest invoking (asynchronous) QueueTransaction with busId=0x%x, trans=0x%x, cb=0x%x\n",(TUint32)a1,trans,cb)); |
|
2446 r = QueueTransaction((TUint32)a1, trans, cb); |
|
2447 if(r!=KErrNone) |
|
2448 { |
|
2449 // The transaction was not queued - since it will not be completed asynchronously, need to remove it here |
|
2450 GetWriteAccess(); |
|
2451 Lock(); |
|
2452 TInt pairIndex=iTransStatArrayByTrans.FindInOrder(pair,TransStatusOrderByTrans); |
|
2453 __ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync ByTrans pairIndex<0",__LINE__)); |
|
2454 iTransStatArrayByTrans.Remove(pairIndex); |
|
2455 pairIndex = iTransStatArrayByStatus.FindInOrder(pair,TransStatusOrderByStatus); |
|
2456 __ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync ByStatus pairIndex<0",__LINE__)); |
|
2457 iTransStatArrayByStatus.Remove(pairIndex); |
|
2458 pairIndex = iTransCbArrayByTrans.FindInOrder(cbPair,TransCbOrderByTrans); |
|
2459 __ASSERT_ALWAYS(pairIndex>=0,Kern::Fault("IIC Client, DoRequest, EQTransAsync Cb by Trans pairIndex<0",__LINE__)); |
|
2460 iTransCbArrayByTrans.Remove(pairIndex); |
|
2461 FreeWriteAccess(); |
|
2462 Unlock(); |
|
2463 Kern::RequestComplete(iClient, aStatus, r); |
|
2464 delete cb; |
|
2465 delete cbPair; |
|
2466 CleanupExtractTrans(pair->iTrans); |
|
2467 CleanupTransaction(pair->iTrans); |
|
2468 delete pair; |
|
2469 } |
|
2470 break; |
|
2471 } |
|
2472 |
|
2473 case(RBusDevIicClient::ECtrlIoTestBufReUse): |
|
2474 { |
|
2475 iStatus = aStatus; |
|
2476 // a1 specifies Bus Realisation Config to use |
|
2477 |
|
2478 // Ensure object pointers are made available |
|
2479 CleanupTransaction(iTrans); |
|
2480 |
|
2481 TInt r = KErrNone; |
|
2482 TIicBusCallback* cb = NULL; |
|
2483 |
|
2484 // Use default constructor to create an empty transaction |
|
2485 iTrans = new TIicBusTransaction(); |
|
2486 if(iTrans == NULL) |
|
2487 { |
|
2488 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iTrans=NULL\n")); |
|
2489 r = KErrNoMemory; |
|
2490 } |
|
2491 |
|
2492 // Create a header for the transaction |
|
2493 if(r == KErrNone) |
|
2494 { |
|
2495 r = CreateDefaultSpiBuf(iSpiBuf); |
|
2496 if(r != KErrNone) |
|
2497 { |
|
2498 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - CreateDefaultSpiBuf returned %d\n",r)); |
|
2499 } |
|
2500 } |
|
2501 |
|
2502 // Create and add transfer lists for half-duplex and full-duplex entries in the transaction |
|
2503 if(r == KErrNone) |
|
2504 { |
|
2505 // Use simple text as payload, 8bit granularity, half-duplex write, full-duplex read (ie payload ignored) |
|
2506 _LIT(halfDuplexText1,"Half Duplex Text 1"); |
|
2507 TBuf8<19> halfDuplexBuf_8; |
|
2508 halfDuplexBuf_8.Copy(halfDuplexText1); |
|
2509 iTfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite, 8, &halfDuplexBuf_8); |
|
2510 if(iTfer == NULL) |
|
2511 { |
|
2512 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iTfer=NULL\n")); |
|
2513 r = KErrNoMemory; |
|
2514 } |
|
2515 else |
|
2516 { |
|
2517 _LIT(halfDuplexText2,"Half Duplex Text 2"); |
|
2518 TBuf8<19> halfDuplexBuf2_8; |
|
2519 halfDuplexBuf2_8.Copy(halfDuplexText2); |
|
2520 TIicBusTransfer* tempHdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterWrite, 8, &halfDuplexBuf2_8); |
|
2521 if(tempHdTfer == NULL) |
|
2522 { |
|
2523 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - tempHdTfer=NULL\n")); |
|
2524 r = KErrNoMemory; |
|
2525 } |
|
2526 else |
|
2527 { |
|
2528 iTfer->LinkAfter(tempHdTfer); |
|
2529 } |
|
2530 } |
|
2531 if(r == KErrNone) |
|
2532 { |
|
2533 _LIT(fullDuplexText1,"Full Duplex Text 1"); |
|
2534 TBuf8<19> fullDuplexBuf1_8; |
|
2535 fullDuplexBuf1_8.Copy(fullDuplexText1); |
|
2536 iFdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterRead, 8, &fullDuplexBuf1_8); |
|
2537 if(iFdTfer == NULL) |
|
2538 { |
|
2539 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - iFdTfer=NULL\n")); |
|
2540 r = KErrNoMemory; |
|
2541 } |
|
2542 else |
|
2543 { |
|
2544 _LIT(fullDuplexText2,"Full Duplex Text 2"); |
|
2545 TBuf8<19> fullDuplexBuf2_8; |
|
2546 fullDuplexBuf2_8.Copy(fullDuplexText2); |
|
2547 TIicBusTransfer* tempFdTfer = new TIicBusTransfer(TIicBusTransfer::EMasterRead, 8, &fullDuplexBuf2_8); |
|
2548 if(tempFdTfer == NULL) |
|
2549 { |
|
2550 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - tempFdTfer=NULL\n")); |
|
2551 r = KErrNoMemory; |
|
2552 } |
|
2553 else |
|
2554 { |
|
2555 iFdTfer->LinkAfter(tempFdTfer); |
|
2556 } |
|
2557 } |
|
2558 } |
|
2559 } |
|
2560 |
|
2561 // Add the Header and Transfers to the Transaction |
|
2562 if(r == KErrNone) |
|
2563 r = iTrans->SetHalfDuplexTrans(iSpiBuf, iTfer); |
|
2564 if(r != KErrNone) |
|
2565 { |
|
2566 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - SetHalfDuplexTrans returned %d\n",r)); |
|
2567 } |
|
2568 |
|
2569 if(r == KErrNone) |
|
2570 r = iTrans->SetFullDuplexTrans(iFdTfer); |
|
2571 if(r != KErrNone) |
|
2572 { |
|
2573 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - SetFullDuplexTrans returned %d\n",r)); |
|
2574 } |
|
2575 |
|
2576 // Specify the callback object to use |
|
2577 if(r == KErrNone) |
|
2578 { |
|
2579 cb = new TIicBusCallback(TransModifCallback, this, iDfcQue, 5); // 5 arbitrary |
|
2580 if(cb == NULL) |
|
2581 { |
|
2582 CLIENT_PRINT(("DChannelIicClient::DoRequest ECtrlIoTestBufReUse ERROR - cb=NULL\n")); |
|
2583 r = KErrNoMemory; |
|
2584 } |
|
2585 } |
|
2586 |
|
2587 // Since the transaction is not yet queued, should be able to modify the transfer and transaction content |
|
2588 TestTransModification(iTrans, iTfer, iFdTfer, iSpiBuf); |
|
2589 |
|
2590 // Store the relevant data in this object's iTransBufReuseData member |
|
2591 iTransBufReuseData.iTransaction = iTrans; |
|
2592 iTransBufReuseData.iHdTfer = iTfer; |
|
2593 iTransBufReuseData.iFdTfer = iFdTfer; |
|
2594 iTransBufReuseData.iHdr = iSpiBuf; |
|
2595 iTransBufReuseData.iCallback = cb; |
|
2596 |
|
2597 // Now queue the transaction. The callback function will re-apply the modification tests and delete the |
|
2598 // objects created here |
|
2599 // If the queueing fails, complete the test here and clean up |
|
2600 r = QueueTransaction((TInt)a1, iTrans, cb); |
|
2601 if(r != KErrNone) |
|
2602 { |
|
2603 Kern::RequestComplete(iClient, iStatus, r); |
|
2604 delete iTransBufReuseData.iCallback; // Must do this before deleting the Transaction in CleanupTransaction |
|
2605 CleanupTransaction(iTrans); |
|
2606 } |
|
2607 break; |
|
2608 } |
|
2609 default: |
|
2610 { |
|
2611 CLIENT_PRINT(("DChannelIicClient::DoRequest - unrecognised value for aId=0x%x\n",aId)); |
|
2612 r=KErrArgument; |
|
2613 break; |
|
2614 } |
|
2615 } |
|
2616 return r; |
|
2617 } |
|
2618 |
|
2619 |
|
2620 // Support for MasterSlave processing |
|
2621 static void MsSlaveClientCallbackFunc(TInt aChannelId, TInt aReturn, TInt aTrigger, TInt16 aRxWords, TInt16 aTxWords, TAny* aParam) |
|
2622 { |
|
2623 CLIENT_PRINT(("> MsSlaveClientCallbackFunc() - aChannelId=0x%x,aReturn=%d,aTrigger=0x%x,aRxWords=0x%x,aTxWords=0x%x,aParam=0x%x\n",aChannelId,aReturn,aTrigger,aRxWords,aTxWords,aParam)); |
|
2624 (void)aTxWords; // Unused if CLIENT_PRINT is disabled |
|
2625 (void)aRxWords; // Unused if CLIENT_PRINT is disabled |
|
2626 DChannelIicClient* channel = (DChannelIicClient*)aParam; |
|
2627 CLIENT_PRINT(("MsSlaveClientCallbackFunc() - channel=0x%x\n",channel)); |
|
2628 if(aTrigger == EAsyncCaptChan) |
|
2629 { |
|
2630 CLIENT_PRINT(("MsSlaveClientCallbackFunc: capture channel completed\n")); |
|
2631 // Set iChannelId, and write to user-side variable. |
|
2632 channel->iChannelId=aChannelId; |
|
2633 TInt r=Kern::ThreadRawWrite(channel->iClient,channel->iClientChanId,&aChannelId,sizeof(TInt)); |
|
2634 if(r == KErrNone) |
|
2635 r=aReturn; |
|
2636 channel->RequestComplete(r); // Inform user of error |
|
2637 return; |
|
2638 } |
|
2639 else |
|
2640 { |
|
2641 CLIENT_PRINT(("\nMsSlaveClientCallbackFunc: trigger condition 0x%x is not recognised \n\n",aTrigger)); |
|
2642 channel->RequestComplete(aReturn); // Inform user of error |
|
2643 } |
|
2644 } |
|
2645 |
|
2646 void DChannelIicClient::RequestComplete(TInt r) |
|
2647 { |
|
2648 Kern::RequestComplete(iClient, iStatus, r); |
|
2649 } |
|
2650 |
|
2651 |
|
2652 TInt DChannelIicClient::InitSlaveClient() |
|
2653 { |
|
2654 iNotif = new TIicBusSlaveCallback(MsSlaveClientCallbackFunc, (TAny*)this, iDfcQue, KIicSlaveClientDfcPriority); |
|
2655 if(iNotif == NULL) |
|
2656 { |
|
2657 CLIENT_PRINT(("> DChannelIicClient::InitSlaveClient ERROR unable to allocate space TIicBusSlaveCallback* iNotif \n")); |
|
2658 return KErrNoMemory; |
|
2659 } |
|
2660 return KErrNone; |
|
2661 } |
|
2662 |