|
1 // Copyright (c) 2000-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/device/t_usbco2.cpp |
|
15 // USB Test Program T_USB, functional part. |
|
16 // Device-side part, to work against USBRFLCT running on the host. |
|
17 // |
|
18 // |
|
19 |
|
20 #include <e32hal.h> |
|
21 #include <e32uid.h> |
|
22 #include <hal.h> |
|
23 |
|
24 #include "t_usb.h" // CActiveConsole, CActiveRW |
|
25 #include "t_usblib.h" // Helpers |
|
26 |
|
27 |
|
28 _LIT(KUsbLddFilename, "eusbc"); // .ldd assumed - it's a filename |
|
29 _LIT(KOtgdiLddFilename, "otgdi"); |
|
30 _LIT(KUsbDeviceName, "Usbc"); |
|
31 _LIT(KFileName, "\\T_USBFILE.BIN"); |
|
32 _LIT(KActivePanic, "T_USB"); |
|
33 |
|
34 static const TUint32 KTusbVersion = 20070524; // just an edit date really |
|
35 static const TUint8 KUsbrflctVersionMajor = 1; // the version we're compatible with |
|
36 static const TUint8 KUsbrflctVersionMinor = 5; |
|
37 static const TUint8 KUsbrflctVersionMicro = 0; |
|
38 |
|
39 static const TInt KMaxFileSize = 100 * 1024 * 1024; // 100MB (requires at least 128MB card) |
|
40 static const TInt KInitialBufSz = 0; |
|
41 static const TInt stridx1 = 0xCC; |
|
42 static const TInt stridx2 = 0xEE; |
|
43 |
|
44 // |
|
45 // --- class CActiveConsole --------------------------------------------------------- |
|
46 // |
|
47 |
|
48 CActiveConsole::CActiveConsole(CConsoleBase* aConsole, TBool aVerboseOutput) |
|
49 : CActive(EPriorityNormal), |
|
50 iConsole(aConsole), |
|
51 iRW(NULL), |
|
52 iBufferSizeChosen(EFalse), |
|
53 iBandwidthPriorityChosen(EFalse), |
|
54 iDMAChosen(EFalse), |
|
55 iDoubleBufferingChosen(EFalse), |
|
56 iSoftwareConnect(EFalse), |
|
57 iHighSpeed(EFalse), |
|
58 iOtg(EFalse), |
|
59 iVerbose(aVerboseOutput) |
|
60 {} |
|
61 |
|
62 |
|
63 CActiveConsole* CActiveConsole::NewLC(CConsoleBase* aConsole, TBool aVerboseOutput) |
|
64 { |
|
65 CActiveConsole* self = new (ELeave) CActiveConsole(aConsole, aVerboseOutput); |
|
66 CleanupStack::PushL(self); |
|
67 self->ConstructL(); |
|
68 return self; |
|
69 } |
|
70 |
|
71 |
|
72 CActiveConsole* CActiveConsole::NewL(CConsoleBase* aConsole, TBool aVerboseOutput) |
|
73 { |
|
74 CActiveConsole* self = NewLC(aConsole, aVerboseOutput); |
|
75 CleanupStack::Pop(); |
|
76 return self; |
|
77 } |
|
78 |
|
79 |
|
80 void CActiveConsole::ConstructL() |
|
81 { |
|
82 CActiveScheduler::Add(this); |
|
83 |
|
84 // Load logical driver (LDD) |
|
85 // (There's no physical driver (PDD) with USB: it's a kernel extension DLL which |
|
86 // was already loaded at boot time.) |
|
87 TInt r = User::LoadLogicalDevice(KUsbLddFilename); |
|
88 if (r != KErrNone && r != KErrAlreadyExists) |
|
89 { |
|
90 TUSB_PRINT1("Error %d on loading USB LDD", r); |
|
91 User::Leave(-1); |
|
92 return; |
|
93 } |
|
94 TUSB_PRINT("Successfully loaded USB LDD"); |
|
95 |
|
96 // Open USB channel |
|
97 r = iPort.Open(0); |
|
98 if (r != KErrNone) |
|
99 { |
|
100 TUSB_PRINT1("Error %d on opening USB port", r); |
|
101 User::Leave(-1); |
|
102 return; |
|
103 } |
|
104 TUSB_PRINT("Successfully opened USB port"); |
|
105 |
|
106 // Create Reader/Writer active object |
|
107 iRW = CActiveRW::NewL(iConsole, &iPort, iVerbose); |
|
108 if (!iRW) |
|
109 { |
|
110 TUSB_PRINT("Failed to create reader/writer"); |
|
111 User::Leave(-1); |
|
112 return; |
|
113 } |
|
114 TUSB_PRINT("Created reader/writer"); |
|
115 |
|
116 // Check for OTG support |
|
117 TBuf8<KUsbDescSize_Otg> otg_desc; |
|
118 r = iPort.GetOtgDescriptor(otg_desc); |
|
119 if (!(r == KErrNotSupported || r == KErrNone)) |
|
120 { |
|
121 TUSB_PRINT1("Error %d while fetching OTG descriptor", r); |
|
122 User::Leave(-1); |
|
123 return; |
|
124 } |
|
125 iOtg = (r != KErrNotSupported) ? ETrue : EFalse; |
|
126 |
|
127 // On an OTG device we have to start the OTG driver, otherwise the Client |
|
128 // stack will remain disabled forever. |
|
129 if (iOtg) |
|
130 { |
|
131 TUSB_PRINT("Running on OTG device: loading OTG driver"); |
|
132 r = User::LoadLogicalDevice(KOtgdiLddFilename); |
|
133 if (r != KErrNone) |
|
134 { |
|
135 TUSB_PRINT1("Error %d on loading OTG LDD", r); |
|
136 User::Leave(-1); |
|
137 return; |
|
138 } |
|
139 r = iOtgPort.Open(); |
|
140 if (r != KErrNone) |
|
141 { |
|
142 TUSB_PRINT1("Error %d on opening OTG port", r); |
|
143 User::Leave(-1); |
|
144 return; |
|
145 } |
|
146 r = iOtgPort.StartStacks(); |
|
147 if (r != KErrNone) |
|
148 { |
|
149 TUSB_PRINT1("Error %d on starting USB stack", r); |
|
150 User::Leave(-1); |
|
151 return; |
|
152 } |
|
153 } |
|
154 } |
|
155 |
|
156 |
|
157 TInt CActiveConsole::SetupInterface() |
|
158 { |
|
159 // Query the USB device/Setup the USB interface |
|
160 TInt r = QueryUsbClientL(); |
|
161 if (r != KErrNone) |
|
162 { |
|
163 TUSB_PRINT1("Interface setup failed", r); |
|
164 return r; |
|
165 } |
|
166 TUSB_PRINT("Interface successfully set up"); |
|
167 |
|
168 // Change some descriptors to contain suitable values |
|
169 r = SetupDescriptors(); |
|
170 if (r != KErrNone) |
|
171 { |
|
172 TUSB_PRINT1("Descriptor setup failed", r); |
|
173 return r; |
|
174 } |
|
175 |
|
176 // Create device state active object |
|
177 iDeviceStateNotifier = CActiveDeviceStateNotifier::NewL(iConsole, &iPort, iVerbose); |
|
178 if (!iDeviceStateNotifier) |
|
179 { |
|
180 TUSB_PRINT("Failed to create device state notifier"); |
|
181 return r; |
|
182 } |
|
183 iDeviceStateNotifier->Activate(); |
|
184 |
|
185 // Create endpoint stall status active object |
|
186 iStallNotifier = CActiveStallNotifier::NewL(iConsole, &iPort, iVerbose); |
|
187 if (!iStallNotifier) |
|
188 { |
|
189 TUSB_PRINT("Failed to create stall notifier"); |
|
190 return r; |
|
191 } |
|
192 iStallNotifier->Activate(); |
|
193 |
|
194 return r; |
|
195 } |
|
196 |
|
197 |
|
198 CActiveConsole::~CActiveConsole() |
|
199 { |
|
200 TUSB_VERBOSE_PRINT("CActiveConsole::~CActiveConsole()"); |
|
201 Cancel(); // base class cancel -> calls our DoCancel |
|
202 delete iRW; // destroy the reader/writer |
|
203 delete iDeviceStateNotifier; |
|
204 delete iStallNotifier; |
|
205 TInt r = iPort.RemoveStringDescriptor(stridx1); |
|
206 if (r != KErrNone) |
|
207 { |
|
208 TUSB_PRINT1("Error %d on string removal", r); |
|
209 } |
|
210 r = iPort.RemoveStringDescriptor(stridx2); |
|
211 if (r != KErrNone) |
|
212 { |
|
213 TUSB_PRINT1("Error %d on string removal", r); |
|
214 } |
|
215 if (iOtg) |
|
216 { |
|
217 TUSB_PRINT("Running on OTG device: unloading OTG driver"); |
|
218 iOtgPort.StopStacks(); |
|
219 iOtgPort.Close(); |
|
220 r = User::FreeLogicalDevice(RUsbOtgDriver::Name()); |
|
221 if (r != KErrNone) |
|
222 { |
|
223 TUSB_PRINT1("Error %d on freeing OTG LDD", r); |
|
224 } |
|
225 } |
|
226 iPort.Close(); // close USB channel |
|
227 r = User::FreeLogicalDevice(KUsbDeviceName); |
|
228 if (r != KErrNone) |
|
229 { |
|
230 TUSB_PRINT1("Error %d during unloading USB LDD", r); |
|
231 User::Leave(-1); |
|
232 return; |
|
233 } |
|
234 TUSB_PRINT("Successfully unloaded USB LDD"); |
|
235 } |
|
236 |
|
237 |
|
238 void CActiveConsole::DoCancel() |
|
239 { |
|
240 TUSB_VERBOSE_PRINT("CActiveConsole::DoCancel()"); |
|
241 iConsole->ReadCancel(); |
|
242 } |
|
243 |
|
244 |
|
245 void CActiveConsole::RunL() |
|
246 { |
|
247 TUSB_VERBOSE_PRINT("CActiveConsole::RunL()"); |
|
248 ProcessKeyPressL(static_cast<TChar>(iConsole->KeyCode())); |
|
249 } |
|
250 |
|
251 |
|
252 void CActiveConsole::RequestCharacter() |
|
253 { |
|
254 // A request is issued to the CConsoleBase to accept a character from the keyboard. |
|
255 __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666)); |
|
256 if (!iBufferSizeChosen) |
|
257 { |
|
258 iConsole->Printf(_L("\n")); |
|
259 iConsole->Printf(_L("++++ Choose max. Transfer Size ++++\n")); |
|
260 iConsole->Printf(_L(" '0' - Set up USB device for USBCV\n")); |
|
261 iConsole->Printf(_L(" '1' - 32 bytes\n")); |
|
262 iConsole->Printf(_L(" '2' - 1024 bytes\n")); |
|
263 iConsole->Printf(_L(" '3' - 64 kbytes\n")); |
|
264 iConsole->Printf(_L(" '4' - 1 Mbyte\n")); |
|
265 } |
|
266 else if (!iBandwidthPriorityChosen) |
|
267 { |
|
268 iConsole->Printf(_L("\n")); |
|
269 iConsole->Printf(_L("++++ Choose Bandwidth Priority ++++\n")); |
|
270 iConsole->Printf(_L(" '1' - Economical buffering - default\n")); |
|
271 iConsole->Printf(_L(" '2' - More memory than default buffering - Plus1\n")); |
|
272 iConsole->Printf(_L(" '3' - More memory than Plus1 buffering - Plus2\n")); |
|
273 iConsole->Printf(_L(" '4' - Maximum buffering\n")); |
|
274 } |
|
275 else if (!iDMAChosen) |
|
276 { |
|
277 iConsole->Printf(_L("\n")); |
|
278 iConsole->Printf(_L("++++ Choose Endpoint I/O Transfer Mode ++++\n")); |
|
279 iConsole->Printf(_L(" '1' - Interrupt Mode\n")); |
|
280 iConsole->Printf(_L(" '2' - DMA Mode (recommended)\n")); |
|
281 } |
|
282 else if (!iDoubleBufferingChosen) |
|
283 { |
|
284 iConsole->Printf(_L("\n")); |
|
285 iConsole->Printf(_L("++++ Choose Endpoint FIFO Mode ++++\n")); |
|
286 iConsole->Printf(_L(" '1' - Normal Buffering Mode\n")); |
|
287 iConsole->Printf(_L(" '2' - Double Buffering Mode (recommended)\n")); |
|
288 } |
|
289 else |
|
290 { |
|
291 iConsole->Printf(_L("\n")); |
|
292 iConsole->Printf(_L("++++ Select Program Option ++++\n")); |
|
293 iConsole->Printf(_L(" 'L'oop test\n")); |
|
294 iConsole->Printf(_L(" Loop test with data 'C'ompare\n")); |
|
295 iConsole->Printf(_L(" 'R'eceive-only test (we receive, host transmits)\n")); |
|
296 iConsole->Printf(_L(" 'T'ransmit-only test\n")); |
|
297 iConsole->Printf(_L(" Receive and 'P'ut (write) to File\n")); |
|
298 iConsole->Printf(_L(" Transmit and 'G'et (read) from File\n")); |
|
299 iConsole->Printf(_L(" Signal Remote-'W'akeup to the host\n")); |
|
300 iConsole->Printf(_L(" 'S'top current transfer\n")); |
|
301 #ifdef WITH_DUMP_OPTION |
|
302 iConsole->Printf(_L(" 'D'ump USB regs to debugout\n")); |
|
303 #endif |
|
304 iConsole->Printf(_L(" Re'E'numerate device\n")); |
|
305 iConsole->Printf(_L(" 'Q'uit this app\n")); |
|
306 } |
|
307 iConsole->Read(iStatus); |
|
308 SetActive(); |
|
309 } |
|
310 |
|
311 |
|
312 void CActiveConsole::ProcessKeyPressL(TChar aChar) |
|
313 { |
|
314 if (aChar == EKeyEscape) |
|
315 { |
|
316 RDebug::Print(_L("CActiveConsole: ESC key pressed -> stopping active scheduler...")); |
|
317 CActiveScheduler::Stop(); |
|
318 return; |
|
319 } |
|
320 if (!iBufferSizeChosen) |
|
321 { |
|
322 // Set maximum buffer size from keypress |
|
323 switch (aChar) |
|
324 { |
|
325 case '0': |
|
326 // This is for creating a USB device that just enumerates, |
|
327 // to be used for compliance testing with USBCV. |
|
328 iRW->SetMaxBufSize(0); |
|
329 break; |
|
330 case '1': |
|
331 iRW->SetMaxBufSize(32); |
|
332 break; |
|
333 case '2': |
|
334 iRW->SetMaxBufSize(1024); |
|
335 break; |
|
336 case '3': |
|
337 iRW->SetMaxBufSize(64 * 1024); |
|
338 break; |
|
339 case '4': |
|
340 iRW->SetMaxBufSize(KMaxBufSize); |
|
341 break; |
|
342 default: |
|
343 TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint()); |
|
344 goto request_char; |
|
345 } |
|
346 TUSB_PRINT1("Maximum buffer size set to %d bytes", iRW->MaxBufSize()); |
|
347 iBufferSizeChosen = ETrue; |
|
348 } |
|
349 else if (!iBandwidthPriorityChosen) |
|
350 { |
|
351 // Set bandwidth priority from keypress |
|
352 switch (aChar) |
|
353 { |
|
354 case '1': |
|
355 iBandwidthPriority = EUsbcBandwidthOUTDefault | EUsbcBandwidthINDefault; |
|
356 TUSB_PRINT("Bandwith priority set to default"); |
|
357 break; |
|
358 case '2': |
|
359 iBandwidthPriority = EUsbcBandwidthOUTPlus1 | EUsbcBandwidthINPlus1; |
|
360 TUSB_PRINT("Bandwith priority set to Plus1"); |
|
361 break; |
|
362 case '3': |
|
363 iBandwidthPriority = EUsbcBandwidthOUTPlus2 | EUsbcBandwidthINPlus2; |
|
364 TUSB_PRINT("Bandwith priority set to Plus2"); |
|
365 break; |
|
366 case '4': |
|
367 iBandwidthPriority = EUsbcBandwidthINMaximum | EUsbcBandwidthOUTMaximum; |
|
368 TUSB_PRINT("Bandwith priority set to maximum"); |
|
369 break; |
|
370 default: |
|
371 TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint()); |
|
372 goto request_char; |
|
373 } |
|
374 TUSB_PRINT1("(Set to 0x%08X)", iBandwidthPriority); |
|
375 iBandwidthPriorityChosen = ETrue; |
|
376 |
|
377 TUSB_PRINT("Configuring interface..."); |
|
378 TInt r = SetupInterface(); |
|
379 if (r != KErrNone) |
|
380 { |
|
381 TUSB_PRINT1("Error: %d. Stopping active scheduler...", r); |
|
382 CActiveScheduler::Stop(); |
|
383 return; |
|
384 } |
|
385 } |
|
386 else if (!iDMAChosen) |
|
387 { |
|
388 // Set DMA mode from keypress |
|
389 switch (aChar) |
|
390 { |
|
391 case '1': |
|
392 TUSB_PRINT("- Trying to deallocate endpoint DMA:\n"); |
|
393 DeAllocateEndpointDMA(EEndpoint1); |
|
394 DeAllocateEndpointDMA(EEndpoint2); |
|
395 break; |
|
396 case '2': |
|
397 TUSB_PRINT("- Trying to allocate endpoint DMA:\n"); |
|
398 AllocateEndpointDMA(EEndpoint1); |
|
399 AllocateEndpointDMA(EEndpoint2); |
|
400 break; |
|
401 default: |
|
402 TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint()); |
|
403 goto request_char; |
|
404 } |
|
405 iDMAChosen = ETrue; |
|
406 } |
|
407 else if (!iDoubleBufferingChosen) |
|
408 { |
|
409 // Set Double Buffering from keypress |
|
410 switch (aChar) |
|
411 { |
|
412 case '1': |
|
413 TUSB_PRINT("- Trying to deallocate Double Buffering:\n"); |
|
414 DeAllocateDoubleBuffering(EEndpoint1); |
|
415 DeAllocateDoubleBuffering(EEndpoint2); |
|
416 break; |
|
417 case '2': |
|
418 TUSB_PRINT("- Trying to allocate Double Buffering:\n"); |
|
419 AllocateDoubleBuffering(EEndpoint1); |
|
420 AllocateDoubleBuffering(EEndpoint2); |
|
421 break; |
|
422 default: |
|
423 TUSB_PRINT1("Not a valid input character: %c", aChar.operator TUint()); |
|
424 goto request_char; |
|
425 } |
|
426 iDoubleBufferingChosen = ETrue; |
|
427 |
|
428 // Everything chosen, so let's re-enumerate... |
|
429 TUSB_PRINT("Enumeration..."); |
|
430 TInt r = ReEnumerate(); |
|
431 if (r != KErrNone) |
|
432 { |
|
433 TUSB_PRINT1("Error: %d. Stopping active scheduler...", r); |
|
434 CActiveScheduler::Stop(); |
|
435 return; |
|
436 } |
|
437 TUSB_PRINT("Device successfully re-enumerated\n"); |
|
438 |
|
439 // Make sure program versions match if testing against USBRFLCT |
|
440 if (iRW->MaxBufSize() != 0) |
|
441 { |
|
442 r = iRW->ExchangeVersions(); |
|
443 if (r != KErrNone) |
|
444 { |
|
445 TUSB_PRINT1("Error: %d. Stopping active scheduler...", r); |
|
446 CActiveScheduler::Stop(); |
|
447 return; |
|
448 } |
|
449 } |
|
450 } |
|
451 else |
|
452 { |
|
453 // Execute one of the 'proper' program functions |
|
454 switch (aChar) |
|
455 { |
|
456 case 'l': // start loop test |
|
457 case 'L': |
|
458 TUSB_PRINT("-> Loop test selected\n"); |
|
459 iRW->SetTransferMode(ELoop); |
|
460 iRW->SendPreamble(); |
|
461 break; |
|
462 case 'c': // start loop/compare test |
|
463 case 'C': |
|
464 TUSB_PRINT("-> Loop test with compare selected\n"); |
|
465 iRW->SetTransferMode(ELoopComp); |
|
466 iRW->SendPreamble(); |
|
467 break; |
|
468 case 'r': // start receive-only test |
|
469 case 'R': |
|
470 TUSB_PRINT("-> Receive-only test selected\n"); |
|
471 iRW->SetTransferMode(EReceiveOnly); |
|
472 iRW->SendPreamble(); |
|
473 break; |
|
474 case 't': // start transmit-only test |
|
475 case 'T': |
|
476 TUSB_PRINT("-> Transmit-only test selected\n"); |
|
477 iRW->SetTransferMode(ETransmitOnly); |
|
478 iRW->SendPreamble(); |
|
479 break; |
|
480 case 'g': // start transmit & get-from-file test |
|
481 case 'G': |
|
482 TUSB_PRINT("-> Transmit from file test selected\n"); |
|
483 iRW->SetTransferMode(ETransmitOnly); |
|
484 iRW->ReadFromDisk(ETrue); |
|
485 iRW->SendPreamble(); |
|
486 break; |
|
487 case 'p': // start receive & put-to-file test |
|
488 case 'P': |
|
489 TUSB_PRINT("-> Receive to file test selected\n"); |
|
490 iRW->SetTransferMode(EReceiveOnly); |
|
491 iRW->WriteToDisk(ETrue); |
|
492 iRW->SendPreamble(); |
|
493 break; |
|
494 case 'w': // remote-wakeup |
|
495 case 'W': |
|
496 TUSB_PRINT("-> Signal Remote-wakeup selected\n"); |
|
497 iPort.SignalRemoteWakeup(); |
|
498 break; |
|
499 case 's': // stop either |
|
500 case 'S': |
|
501 TUSB_PRINT("-> Stop transfer selected\n"); |
|
502 iRW->Stop(); |
|
503 break; |
|
504 #ifdef WITH_DUMP_OPTION |
|
505 case 'd': // dump controller registers |
|
506 case 'D': |
|
507 TUSB_PRINT("-> Dump option selected\n"); |
|
508 iPort.DumpRegisters(); |
|
509 QueryRxBuffer(); |
|
510 break; |
|
511 #endif |
|
512 case 'e': // ReEnumerate() |
|
513 case 'E': |
|
514 TUSB_PRINT("-> Re-enumerate device selected\n"); |
|
515 ReEnumerate(); |
|
516 break; |
|
517 case 'q': // quit |
|
518 case 'Q': |
|
519 TUSB_PRINT("-> Quit program selected\n"); |
|
520 TUSB_VERBOSE_PRINT("CActiveConsole: stopping active scheduler..."); |
|
521 CActiveScheduler::Stop(); |
|
522 return; |
|
523 default: |
|
524 TUSB_PRINT1("-> Not a valid input character: %c", aChar.operator TUint()); |
|
525 goto request_char; |
|
526 } |
|
527 } |
|
528 request_char: |
|
529 RequestCharacter(); |
|
530 return; |
|
531 } |
|
532 |
|
533 |
|
534 #ifdef WITH_DUMP_OPTION |
|
535 void CActiveConsole::QueryRxBuffer() |
|
536 { |
|
537 // Let's look whether there's data in the rx buffer |
|
538 TInt bytes = 0; |
|
539 TInt r = iPort.QueryReceiveBuffer(EEndpoint2, bytes); |
|
540 if (r != KErrNone) |
|
541 { |
|
542 RDebug::Print(_L(" Error %d on querying read buffer\n"), r); |
|
543 } |
|
544 else |
|
545 { |
|
546 RDebug::Print(_L(" %d bytes in RX buffer\n"), bytes); |
|
547 } |
|
548 } |
|
549 #endif |
|
550 |
|
551 |
|
552 TInt CActiveConsole::QueryUsbClientL() |
|
553 { |
|
554 // Not really just querying... but rather setting up the whole interface. |
|
555 // It's in fact a bit lengthy, but all these steps are required, once, |
|
556 // and in that order. |
|
557 |
|
558 // Get device/endpoint capabilities |
|
559 // |
|
560 // A TPckg, or TPckBuf was not used in the following, because |
|
561 // |
|
562 // TPckgBuf<TUsbcEndpointData[KUsbcMaxEndpoints]> databuf; |
|
563 // |
|
564 // doesn't work. Also, |
|
565 // |
|
566 // TUsbcEndpointData data[KUsbcMaxEndpoints]; |
|
567 // TPckgBuf<TUsbcEndpointData[KUsbcMaxEndpoints]> databuf(data); |
|
568 // |
|
569 // doesn't work. Also, |
|
570 // |
|
571 // TUsbcEndpointData data[KUsbcMaxEndpoints]; |
|
572 // TPckgBuf<TUsbcEndpointData[]> databuf(data); |
|
573 // |
|
574 // doesn't work. |
|
575 // So we seem to have to stick to the ugly cast below. |
|
576 // |
|
577 // TUsbcEndpointData data[KUsbcMaxEndpoints]; |
|
578 // TPtr8 databuf(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data)); |
|
579 // |
|
580 |
|
581 // Device |
|
582 TUsbDeviceCaps d_caps; |
|
583 TInt r = iPort.DeviceCaps(d_caps); |
|
584 if (r != KErrNone) |
|
585 { |
|
586 TUSB_PRINT1("Error %d on querying device capabilities", r); |
|
587 return KErrGeneral; |
|
588 } |
|
589 const TInt n = d_caps().iTotalEndpoints; |
|
590 |
|
591 TUSB_PRINT("### USB device capabilities:"); |
|
592 TUSB_PRINT1("Number of endpoints: %d", n); |
|
593 TUSB_PRINT1("Supports Software-Connect: %s", |
|
594 d_caps().iConnect ? _S("yes") : _S("no")); |
|
595 TUSB_PRINT1("Device is Self-Powered: %s", |
|
596 d_caps().iSelfPowered ? _S("yes") : _S("no")); |
|
597 TUSB_PRINT1("Supports Remote-Wakeup: %s", |
|
598 d_caps().iRemoteWakeup ? _S("yes") : _S("no")); |
|
599 TUSB_PRINT1("Supports High-speed: %s", |
|
600 d_caps().iHighSpeed ? _S("yes") : _S("no")); |
|
601 TUSB_PRINT1("Supports OTG: %s", |
|
602 iOtg ? _S("yes") : _S("no")); |
|
603 TUSB_PRINT1("Supports unpowered cable detection: %s", |
|
604 (d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_CableDetectWithoutPower) ? |
|
605 _S("yes") : _S("no")); |
|
606 TUSB_PRINT1("Supports endpoint resource alloc scheme V2: %s\n", |
|
607 (d_caps().iFeatureWord1 & KUsbDevCapsFeatureWord1_EndpointResourceAllocV2) ? |
|
608 _S("yes") : _S("no")); |
|
609 TUSB_PRINT(""); |
|
610 |
|
611 iSoftwareConnect = d_caps().iConnect; // we need to remember this |
|
612 |
|
613 if (n < 2) |
|
614 { |
|
615 TUSB_PRINT1("Error: only %d endpoints available on device", n); |
|
616 return KErrGeneral; |
|
617 } |
|
618 |
|
619 // Endpoints |
|
620 TUsbcEndpointData data[KUsbcMaxEndpoints]; |
|
621 TPtr8 dataptr(reinterpret_cast<TUint8*>(data), sizeof(data), sizeof(data)); |
|
622 r = iPort.EndpointCaps(dataptr); |
|
623 if (r != KErrNone) |
|
624 { |
|
625 TUSB_PRINT1("Error %d on querying endpoint capabilities", r); |
|
626 return KErrGeneral; |
|
627 } |
|
628 TUSB_PRINT("### USB device endpoint capabilities:"); |
|
629 for (TInt i = 0; i < n; i++) |
|
630 { |
|
631 const TUsbcEndpointCaps* caps = &data[i].iCaps; |
|
632 TUSB_PRINT2("Endpoint: SizeMask = 0x%08x TypeDirMask = 0x%08x", |
|
633 caps->iSizes, caps->iTypesAndDir); |
|
634 } |
|
635 TUSB_PRINT(""); |
|
636 |
|
637 // Set up the active interface |
|
638 TUsbcInterfaceInfoBuf ifc; |
|
639 TInt ep_found = 0; |
|
640 TBool foundBulkIN = EFalse; |
|
641 TBool foundBulkOUT = EFalse; |
|
642 for (TInt i = 0; i < n; i++) |
|
643 { |
|
644 const TUsbcEndpointCaps* const caps = &data[i].iCaps; |
|
645 const TInt mps = caps->MaxPacketSize(); |
|
646 if (!foundBulkIN && |
|
647 (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirIn)) == |
|
648 (KUsbEpTypeBulk | KUsbEpDirIn)) |
|
649 { |
|
650 if (!(mps == 64 || mps == 512)) |
|
651 { |
|
652 TUSB_PRINT1("Funny Bulk IN MaxPacketSize: %d - T_USB will probably fail...", mps); |
|
653 } |
|
654 // EEndpoint1 is going to be our Tx (IN) endpoint |
|
655 ifc().iEndpointData[0].iType = KUsbEpTypeBulk; |
|
656 ifc().iEndpointData[0].iDir = KUsbEpDirIn; |
|
657 ifc().iEndpointData[0].iSize = mps; |
|
658 foundBulkIN = ETrue; |
|
659 if (++ep_found == 2) |
|
660 break; |
|
661 } |
|
662 else if (!foundBulkOUT && |
|
663 (caps->iTypesAndDir & (KUsbEpTypeBulk | KUsbEpDirOut)) == |
|
664 (KUsbEpTypeBulk | KUsbEpDirOut)) |
|
665 { |
|
666 if (!(mps == 64 || mps == 512)) |
|
667 { |
|
668 TUSB_PRINT1("Funny Bulk OUT MaxPacketSize: %d - T_USB will probably fail...", mps); |
|
669 } |
|
670 // EEndpoint2 is going to be our Rx (OUT) endpoint |
|
671 ifc().iEndpointData[1].iType = KUsbEpTypeBulk; |
|
672 ifc().iEndpointData[1].iDir = KUsbEpDirOut; |
|
673 ifc().iEndpointData[1].iSize = mps; |
|
674 foundBulkOUT = ETrue; |
|
675 if (++ep_found == 2) |
|
676 break; |
|
677 } |
|
678 } |
|
679 if (ep_found != 2) |
|
680 { |
|
681 TUSB_PRINT1("No suitable endpoints found", r); |
|
682 return KErrGeneral; |
|
683 } |
|
684 |
|
685 _LIT16(ifcname, "T_USB Test Interface (Default Setting 0)"); |
|
686 ifc().iString = const_cast<TDesC16*>(&ifcname); |
|
687 ifc().iTotalEndpointsUsed = 2; |
|
688 ifc().iClass.iClassNum = 0xff; // vendor-specific |
|
689 ifc().iClass.iSubClassNum = 0xff; // vendor-specific |
|
690 ifc().iClass.iProtocolNum = 0xff; // vendor-specific |
|
691 r = iPort.SetInterface(0, ifc, iBandwidthPriority); |
|
692 if (r != KErrNone) |
|
693 { |
|
694 TUSB_PRINT1("Error %d on setting active interface", r); |
|
695 } |
|
696 |
|
697 // Find ep's for an alternate ifc setting. |
|
698 // We're not really going to use it, but it gives USBCV et al. more stuff to play with. |
|
699 if (!SupportsAlternateInterfaces()) |
|
700 { |
|
701 TUSB_PRINT("Alternate Interfaces not supported - skipping alternate setting setup\n"); |
|
702 return KErrNone; |
|
703 } |
|
704 ep_found = 0; |
|
705 TBool foundIsoIN = EFalse; |
|
706 TBool foundIsoOUT = EFalse; |
|
707 |
|
708 // NB! We cannot assume that any specific device has any given set of |
|
709 // capabilities, so whilst we try and set an assortment of endpoint types |
|
710 // we may not get what we want. |
|
711 |
|
712 // Also, note that the endpoint[] array in the interface descriptor |
|
713 // must be filled from ep[0]...ep[n-1]. |
|
714 |
|
715 for (TInt i = 0; i < n; i++) |
|
716 { |
|
717 const TUsbcEndpointCaps* const caps = &data[i].iCaps; |
|
718 const TInt mps = caps->MaxPacketSize(); |
|
719 if (!foundIsoIN && |
|
720 (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirIn)) == |
|
721 (KUsbEpTypeIsochronous | KUsbEpDirIn)) |
|
722 { |
|
723 // This is going to be our Iso TX (IN) endpoint |
|
724 ifc().iEndpointData[ep_found].iType = KUsbEpTypeIsochronous; |
|
725 ifc().iEndpointData[ep_found].iDir = KUsbEpDirIn; |
|
726 ifc().iEndpointData[ep_found].iSize = mps; |
|
727 ifc().iEndpointData[ep_found].iInterval = 0x01; // 2^(bInterval-1)ms, bInterval must be [1..16] |
|
728 ifc().iEndpointData[ep_found].iInterval_Hs = 0x01; // same as for FS |
|
729 ifc().iEndpointData[ep_found].iExtra = 2; // 2 extra bytes for Audio Class EP descriptor |
|
730 foundIsoIN = ETrue; |
|
731 if (++ep_found == 2) |
|
732 break; |
|
733 } |
|
734 else if (!foundIsoOUT && |
|
735 (caps->iTypesAndDir & (KUsbEpTypeIsochronous | KUsbEpDirOut)) == |
|
736 (KUsbEpTypeIsochronous | KUsbEpDirOut)) |
|
737 { |
|
738 // This is going to be our Iso RX (OUT) endpoint |
|
739 ifc().iEndpointData[ep_found].iType = KUsbEpTypeIsochronous; |
|
740 ifc().iEndpointData[ep_found].iDir = KUsbEpDirOut; |
|
741 ifc().iEndpointData[ep_found].iSize = mps; |
|
742 ifc().iEndpointData[ep_found].iInterval = 0x01; // 2^(bInterval-1)ms, bInterval must be [1..16] |
|
743 ifc().iEndpointData[ep_found].iExtra = 2; // 2 extra bytes for Audio Class EP descriptor |
|
744 foundIsoOUT = ETrue; |
|
745 if (++ep_found == 2) |
|
746 break; |
|
747 } |
|
748 } |
|
749 // Let's try to add Bulk endpoints up to the max # of 2. |
|
750 if (ep_found < 2) |
|
751 { |
|
752 for (TInt i = 0; i < n; i++) |
|
753 { |
|
754 const TUsbcEndpointCaps* const caps = &data[i].iCaps; |
|
755 const TUint mps = caps->MaxPacketSize(); |
|
756 if (caps->iTypesAndDir & KUsbEpTypeBulk) |
|
757 { |
|
758 const TUint dir = (caps->iTypesAndDir & KUsbEpDirIn) ? KUsbEpDirIn : KUsbEpDirOut; |
|
759 ifc().iEndpointData[ep_found].iType = KUsbEpTypeBulk; |
|
760 ifc().iEndpointData[ep_found].iDir = dir; |
|
761 ifc().iEndpointData[ep_found].iSize = mps; |
|
762 if (++ep_found == 2) |
|
763 break; |
|
764 } |
|
765 } |
|
766 } |
|
767 if (ep_found == 0) |
|
768 { |
|
769 TUSB_PRINT("Not enough suitable endpoints found for alt ifc"); |
|
770 // not a disaster though |
|
771 return KErrNone; |
|
772 } |
|
773 |
|
774 _LIT16(ifcname1, "T_USB Test Interface (Alternate Setting 1)"); |
|
775 ifc().iString = const_cast<TDesC16*>(&ifcname1); |
|
776 ifc().iTotalEndpointsUsed = ep_found; |
|
777 ifc().iClass.iClassNum = KUsbAudioInterfaceClassCode; |
|
778 ifc().iClass.iSubClassNum = KUsbAudioInterfaceSubclassCode_Audiostreaming; |
|
779 ifc().iClass.iProtocolNum = KUsbAudioInterfaceProtocolCode_Pr_Protocol_Undefined; |
|
780 // Tell the driver that this setting is not interested in Ep0 requests: |
|
781 ifc().iFeatureWord |= KUsbcInterfaceInfo_NoEp0RequestsPlease; |
|
782 r = iPort.SetInterface(1, ifc); |
|
783 if (r != KErrNone) |
|
784 { |
|
785 TUSB_PRINT1("Error %d on setting alternate interface", r); |
|
786 } |
|
787 |
|
788 return r; |
|
789 } |
|
790 |
|
791 |
|
792 void CActiveConsole::AllocateEndpointDMA(TEndpointNumber aEndpoint) |
|
793 { |
|
794 TInt r = iPort.AllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDMA); |
|
795 if (r == KErrNone) |
|
796 RDebug::Print(_L("DMA allocation on endpoint %d: KErrNone"), aEndpoint); |
|
797 else if (r == KErrInUse) |
|
798 RDebug::Print(_L("DMA allocation on endpoint %d: KErrInUse"), aEndpoint); |
|
799 else if (r == KErrNotSupported) |
|
800 RDebug::Print(_L("DMA allocation on endpoint %d: KErrNotSupported"), aEndpoint); |
|
801 else |
|
802 RDebug::Print(_L("DMA allocation on endpoint %d: unexpected return value %d"), |
|
803 aEndpoint, r); |
|
804 TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDMA); |
|
805 TUSB_PRINT2("DMA on endpoint %d %s\n", |
|
806 aEndpoint, res ? _S("allocated") : _S("not allocated")); |
|
807 |
|
808 if ((r == KErrNone) && !res) |
|
809 RDebug::Print(_L("(Allocation success but negative query result: contradiction!)\n")); |
|
810 else if ((r != KErrNone) && res) |
|
811 RDebug::Print(_L("(Allocation failure but positive query result: contradiction!)\n")); |
|
812 } |
|
813 |
|
814 |
|
815 void CActiveConsole::DeAllocateEndpointDMA(TEndpointNumber aEndpoint) |
|
816 { |
|
817 TInt r = iPort.DeAllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDMA); |
|
818 if (r == KErrNone) |
|
819 RDebug::Print(_L("DMA deallocation on endpoint %d: KErrNone"), aEndpoint); |
|
820 else if (r == KErrNotSupported) |
|
821 RDebug::Print(_L("DMA deallocation on endpoint %d: KErrNotSupported"), aEndpoint); |
|
822 else |
|
823 RDebug::Print(_L("DMA deallocation on endpoint %d: unexpected return value %d"), |
|
824 aEndpoint, r); |
|
825 TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDMA); |
|
826 TUSB_PRINT2("DMA on endpoint %d %s\n", |
|
827 aEndpoint, res ? _S("allocated") : _S("not allocated")); |
|
828 } |
|
829 |
|
830 |
|
831 void CActiveConsole::AllocateDoubleBuffering(TEndpointNumber aEndpoint) |
|
832 { |
|
833 TInt r = iPort.AllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDoubleBuffering); |
|
834 if (r == KErrNone) |
|
835 RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrNone"), aEndpoint); |
|
836 else if (r == KErrInUse) |
|
837 RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrInUse"), aEndpoint); |
|
838 else if (r == KErrNotSupported) |
|
839 RDebug::Print(_L("Double Buffering allocation on endpoint %d: KErrNotSupported"), aEndpoint); |
|
840 else |
|
841 RDebug::Print(_L("Double Buffering allocation on endpoint %d: unexpected return value %d"), |
|
842 aEndpoint, r); |
|
843 TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDoubleBuffering); |
|
844 TUSB_PRINT2("Double Buffering on endpoint %d %s\n", |
|
845 aEndpoint, res ? _S("allocated") : _S("not allocated")); |
|
846 |
|
847 if ((r == KErrNone) && !res) |
|
848 RDebug::Print(_L("(Allocation success but negative query result: contradiction!)\n")); |
|
849 else if ((r != KErrNone) && res) |
|
850 RDebug::Print(_L("(Allocation failure but positive query result: contradiction!)\n")); |
|
851 } |
|
852 |
|
853 |
|
854 void CActiveConsole::DeAllocateDoubleBuffering(TEndpointNumber aEndpoint) |
|
855 { |
|
856 TInt r = iPort.DeAllocateEndpointResource(aEndpoint, EUsbcEndpointResourceDoubleBuffering); |
|
857 if (r == KErrNone) |
|
858 RDebug::Print(_L("Double Buffering deallocation on endpoint %d: KErrNone"), aEndpoint); |
|
859 else if (r == KErrNotSupported) |
|
860 RDebug::Print(_L("Double Buffering deallocation on endpoint %d: KErrNotSupported"), aEndpoint); |
|
861 else |
|
862 RDebug::Print(_L("Double Buffering deallocation on endpoint %d: unexpected return value %d"), |
|
863 aEndpoint, r); |
|
864 TBool res = iPort.QueryEndpointResourceUse(aEndpoint, EUsbcEndpointResourceDoubleBuffering); |
|
865 TUSB_PRINT2("Double Buffering on endpoint %d %s\n", |
|
866 aEndpoint, res ? _S("allocated") : _S("not allocated")); |
|
867 } |
|
868 |
|
869 |
|
870 TInt CActiveConsole::ReEnumerate() |
|
871 { |
|
872 TRequestStatus enum_status; |
|
873 iPort.ReEnumerate(enum_status); |
|
874 if (!iSoftwareConnect) |
|
875 { |
|
876 iConsole->Printf(_L("This device does not support software\n")); |
|
877 iConsole->Printf(_L("disconnect/reconnect\n")); |
|
878 iConsole->Printf(_L("Please physically unplug and replug\n")); |
|
879 iConsole->Printf(_L("the USB cable NOW... ")); |
|
880 } |
|
881 iConsole->Printf(_L("\n>>> START THE USBRFLCT PROGRAM ON THE HOST SIDE NOW <<<\n")); |
|
882 User::WaitForRequest(enum_status); |
|
883 if (enum_status != KErrNone) |
|
884 { |
|
885 TUSB_PRINT1("Error: Re-enumeration status = %d", enum_status.Int()); |
|
886 return KErrGeneral; |
|
887 } |
|
888 TUsbcDeviceState device_state = EUsbcDeviceStateUndefined; |
|
889 TInt r = iPort.DeviceStatus(device_state); |
|
890 if (r != KErrNone) |
|
891 { |
|
892 TUSB_PRINT1("Error %d on querying device state", r); |
|
893 } |
|
894 else |
|
895 { |
|
896 TUSB_PRINT1("Current device state: %s", |
|
897 (device_state == EUsbcDeviceStateUndefined) ? _S("Undefined") : |
|
898 ((device_state == EUsbcDeviceStateAttached) ? _S("Attached") : |
|
899 ((device_state == EUsbcDeviceStatePowered) ? _S("Powered") : |
|
900 ((device_state == EUsbcDeviceStateDefault) ? _S("Default") : |
|
901 ((device_state == EUsbcDeviceStateAddress) ? _S("Address") : |
|
902 ((device_state == EUsbcDeviceStateConfigured) ? _S("Configured") : |
|
903 ((device_state == EUsbcDeviceStateSuspended) ? _S("Suspended") : |
|
904 _S("Unknown")))))))); |
|
905 } |
|
906 |
|
907 // Check the speed of the established physical USB connection |
|
908 iHighSpeed = iPort.CurrentlyUsingHighSpeed(); |
|
909 if (iHighSpeed) |
|
910 { |
|
911 TUSB_PRINT("---> USB High-speed Testing\n"); |
|
912 // It can only be 512 bytes when using high-speed. |
|
913 iRW->SetMaxPacketSize(512); // iRW already exists at this point |
|
914 } |
|
915 else |
|
916 { |
|
917 TUSB_PRINT("---> USB Full-speed Testing\n"); |
|
918 // We only support 64 bytes when using full-speed. |
|
919 iRW->SetMaxPacketSize(64); // iRW already exists at this point |
|
920 } |
|
921 |
|
922 return KErrNone; |
|
923 } |
|
924 |
|
925 |
|
926 #ifdef test |
|
927 #undef test |
|
928 #endif |
|
929 #define test(x) \ |
|
930 do { \ |
|
931 if (!(x)) \ |
|
932 { \ |
|
933 TUSB_PRINT1("Failure occurred! - on line %d", __LINE__); \ |
|
934 return KErrGeneral; \ |
|
935 } \ |
|
936 } while (0) |
|
937 |
|
938 |
|
939 TInt CActiveConsole::SetupDescriptors() |
|
940 { |
|
941 // === Device Descriptor |
|
942 |
|
943 TInt deviceDescriptorSize = 0; |
|
944 iPort.GetDeviceDescriptorSize(deviceDescriptorSize); |
|
945 test(static_cast<TUint>(deviceDescriptorSize) == KUsbDescSize_Device); |
|
946 |
|
947 TBuf8<KUsbDescSize_Device> deviceDescriptor; |
|
948 TInt r = iPort.GetDeviceDescriptor(deviceDescriptor); |
|
949 test(r == KErrNone); |
|
950 |
|
951 const TInt KUsbSpecOffset = 2; |
|
952 const TInt KUsbVendorIdOffset = 8; |
|
953 const TInt KUsbProductIdOffset = 10; |
|
954 const TInt KUsbDevReleaseOffset = 12; |
|
955 // Change the USB spec number to 2.00 |
|
956 deviceDescriptor[KUsbSpecOffset] = 0x00; |
|
957 deviceDescriptor[KUsbSpecOffset+1] = 0x02; |
|
958 // Change the device vendor ID (VID) to 0x0E22 (Symbian) |
|
959 deviceDescriptor[KUsbVendorIdOffset] = 0x22; // little endian! |
|
960 deviceDescriptor[KUsbVendorIdOffset+1] = 0x0E; |
|
961 // Change the device product ID (PID) to 0x1111 |
|
962 deviceDescriptor[KUsbProductIdOffset] = 0x11; |
|
963 deviceDescriptor[KUsbProductIdOffset+1] = 0x11; |
|
964 // Change the device release number to 3.05 |
|
965 deviceDescriptor[KUsbDevReleaseOffset] = 0x05; |
|
966 deviceDescriptor[KUsbDevReleaseOffset+1] = 0x03; |
|
967 r = iPort.SetDeviceDescriptor(deviceDescriptor); |
|
968 test(r == KErrNone); |
|
969 |
|
970 const TUint16 Vid = (((TUint16)deviceDescriptor[KUsbVendorIdOffset + 1] << 8) & 0xff00) | |
|
971 deviceDescriptor[KUsbVendorIdOffset]; |
|
972 const TUint16 Pid = (((TUint16)deviceDescriptor[KUsbProductIdOffset + 1] << 8) & 0xff00) | |
|
973 deviceDescriptor[KUsbProductIdOffset]; |
|
974 |
|
975 TUSB_PRINT6("\nVID = 0x%04X / PID = 0x%04X / DevRel = %d%d.%d%d\n", Vid, Pid, |
|
976 ((deviceDescriptor[KUsbDevReleaseOffset + 1] >> 4) & 0x0f), |
|
977 (deviceDescriptor[KUsbDevReleaseOffset + 1] & 0x0f), |
|
978 ((deviceDescriptor[KUsbDevReleaseOffset] >> 4) & 0x0f), |
|
979 (deviceDescriptor[KUsbDevReleaseOffset] & 0x0f)); |
|
980 |
|
981 // === Configuration Descriptor |
|
982 |
|
983 TInt configDescriptorSize = 0; |
|
984 iPort.GetConfigurationDescriptorSize(configDescriptorSize); |
|
985 test(static_cast<TUint>(configDescriptorSize) == KUsbDescSize_Config); |
|
986 |
|
987 TBuf8<KUsbDescSize_Config> configDescriptor; |
|
988 r = iPort.GetConfigurationDescriptor(configDescriptor); |
|
989 test(r == KErrNone); |
|
990 |
|
991 // Change the reported max power to 100mA (= 2 * 0x32), |
|
992 // which is the highest value allowed for a bus-powered device. |
|
993 const TInt KUsbMaxPowerOffset = 8; |
|
994 configDescriptor[KUsbMaxPowerOffset] = 0x32; |
|
995 r = iPort.SetConfigurationDescriptor(configDescriptor); |
|
996 test(r == KErrNone); |
|
997 |
|
998 // === String Descriptors |
|
999 |
|
1000 // Set up two arbitrary string descriptors, which can be queried |
|
1001 // manually from the host side for testing purposes (for instance |
|
1002 // using 'usbcheck'). |
|
1003 |
|
1004 _LIT16(string_one, "Arbitrary String Descriptor Test String 1"); |
|
1005 TBuf16<KUsbStringDescStringMaxSize / 2> wr_str(string_one); |
|
1006 r = iPort.SetStringDescriptor(stridx1, wr_str); |
|
1007 test(r == KErrNone); |
|
1008 |
|
1009 _LIT16(string_two, "Another Arbitrary String Descriptor Test String"); |
|
1010 wr_str.FillZ(wr_str.MaxLength()); |
|
1011 wr_str = string_two; |
|
1012 r = iPort.SetStringDescriptor(stridx2, wr_str); |
|
1013 test(r == KErrNone); |
|
1014 |
|
1015 return KErrNone; |
|
1016 } |
|
1017 |
|
1018 |
|
1019 // |
|
1020 // --- class CActiveRW --------------------------------------------------------- |
|
1021 // |
|
1022 |
|
1023 CActiveRW::CActiveRW(CConsoleBase* aConsole, RDevUsbcClient* aPort, TBool aVerboseOutput) |
|
1024 : CActive(EPriorityNormal), |
|
1025 iConsole(aConsole), |
|
1026 iPort(aPort), |
|
1027 iBufSz(KInitialBufSz), |
|
1028 iMaxBufSz(KInitialBufSz), |
|
1029 iMaxPktSz(0), |
|
1030 iCurrentXfer(ENone), |
|
1031 iXferMode(::ENone), |
|
1032 iDoStop(EFalse), |
|
1033 iPktNum(~0), |
|
1034 iVerbose(aVerboseOutput) |
|
1035 { |
|
1036 TUSB_VERBOSE_PRINT("CActiveRW::CActiveRW()"); |
|
1037 } |
|
1038 |
|
1039 |
|
1040 CActiveRW* CActiveRW::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort, TBool aVerboseOutput) |
|
1041 { |
|
1042 CActiveRW* self = new (ELeave) CActiveRW(aConsole, aPort, aVerboseOutput); |
|
1043 CleanupStack::PushL(self); |
|
1044 self->ConstructL(); |
|
1045 CActiveScheduler::Add(self); |
|
1046 CleanupStack::Pop(); // self |
|
1047 return self; |
|
1048 } |
|
1049 |
|
1050 |
|
1051 void CActiveRW::ConstructL() |
|
1052 { |
|
1053 TUSB_VERBOSE_PRINT("CActiveRW::ConstructL()"); |
|
1054 |
|
1055 User::LeaveIfError(iFs.Connect()); |
|
1056 |
|
1057 // Prepare Preamble buffer |
|
1058 iPreambleBuf.SetMax(); |
|
1059 iPreambleBuf.FillZ(); |
|
1060 |
|
1061 // Prepare IN data buffer |
|
1062 iWriteBuf.SetMax(); |
|
1063 for (TInt i = 0; i < iWriteBuf.MaxSize(); i++) |
|
1064 { |
|
1065 iWriteBuf[i] = i; |
|
1066 } |
|
1067 |
|
1068 // Prepare OUT data buffer |
|
1069 iReadBuf.SetMax(); |
|
1070 |
|
1071 // Create read timeout timer active object (but don't activate it yet) |
|
1072 iTimeoutTimer = CActiveTimer::NewL(iConsole, iPort, iVerbose); |
|
1073 if (!iTimeoutTimer) |
|
1074 { |
|
1075 TUSB_PRINT("Failed to create timeout timer"); |
|
1076 } |
|
1077 } |
|
1078 |
|
1079 |
|
1080 CActiveRW::~CActiveRW() |
|
1081 { |
|
1082 TUSB_VERBOSE_PRINT("CActiveRW::~CActiveRW()"); |
|
1083 Cancel(); // base class |
|
1084 delete iTimeoutTimer; |
|
1085 iFile.Close(); |
|
1086 iFs.Close(); |
|
1087 } |
|
1088 |
|
1089 |
|
1090 void CActiveRW::SetMaxBufSize(TInt aBufSz) |
|
1091 { |
|
1092 if (aBufSz > KMaxBufSize) |
|
1093 { |
|
1094 TUSB_PRINT2("SetMaxBufSize(): too large: %d! (using %d)", aBufSz, KMaxBufSize); |
|
1095 aBufSz = KMaxBufSize; |
|
1096 } |
|
1097 iMaxBufSz = aBufSz; |
|
1098 } |
|
1099 |
|
1100 |
|
1101 void CActiveRW::SetMaxPacketSize(TInt aPktSz) |
|
1102 { |
|
1103 iMaxPktSz = aPktSz; |
|
1104 } |
|
1105 |
|
1106 |
|
1107 TInt CActiveRW::MaxBufSize() const |
|
1108 { |
|
1109 return iMaxBufSz; |
|
1110 } |
|
1111 |
|
1112 |
|
1113 void CActiveRW::SetTransferMode(TXferMode aMode) |
|
1114 { |
|
1115 iXferMode = aMode; |
|
1116 if (aMode == EReceiveOnly || aMode == ETransmitOnly) |
|
1117 { |
|
1118 // For streaming transfers we do this only once. |
|
1119 iBufSz = iMaxBufSz; |
|
1120 } |
|
1121 } |
|
1122 |
|
1123 |
|
1124 void CActiveRW::RunL() |
|
1125 { |
|
1126 TUSB_VERBOSE_PRINT("CActiveRW::RunL()"); |
|
1127 if (iStatus != KErrNone) |
|
1128 { |
|
1129 TUSB_PRINT1("Error %d in RunL", iStatus.Int()); |
|
1130 } |
|
1131 if (iDoStop) |
|
1132 { |
|
1133 TUSB_PRINT("Stopped"); |
|
1134 iDoStop = EFalse; |
|
1135 return; |
|
1136 } |
|
1137 switch (iCurrentXfer) |
|
1138 { |
|
1139 case EPreamble: |
|
1140 if (iXferMode != EReceiveOnly) |
|
1141 SendData(); // next we write data |
|
1142 else |
|
1143 ReadData(); // or we read data |
|
1144 break; |
|
1145 case EWriteXfer: |
|
1146 if (iXferMode == ETransmitOnly) |
|
1147 SendData(); // next we send data |
|
1148 else |
|
1149 ReadData(); // or we read data |
|
1150 break; |
|
1151 case EReadXfer: |
|
1152 if (iXferMode == EReceiveOnly) |
|
1153 { |
|
1154 const TUint32 num = *reinterpret_cast<const TUint32*>(iReadBuf.Ptr()); |
|
1155 if (num != ++iPktNum) |
|
1156 { |
|
1157 TUSB_PRINT2("*** rcv'd wrong pkt number: 0x%x (expected: 0x%x)", num, iPktNum); |
|
1158 // Update the packet number with the received number, so that |
|
1159 // if a single packet is duplicated or lost then a single error occurs |
|
1160 iPktNum = num; |
|
1161 } |
|
1162 if (iDiskAccessEnabled) |
|
1163 { |
|
1164 // Write out to disk previous completed Read |
|
1165 TUSB_VERBOSE_PRINT2("iMaxBufSz = %d (iReadBuf.Size(): %d)", |
|
1166 iMaxBufSz, iReadBuf.Size()); |
|
1167 WriteBufferToDisk(iReadBuf, iMaxBufSz); |
|
1168 } |
|
1169 ReadData(); // next we read data |
|
1170 break; |
|
1171 } |
|
1172 if (iXferMode == ELoopComp) |
|
1173 { |
|
1174 if (!CompareBuffers(iBufSz)) |
|
1175 { |
|
1176 TUSB_PRINT1("Error while comparing tx & rx buffers for packet 0x%x", iPktNum); |
|
1177 } |
|
1178 } |
|
1179 else if (iBufSz > 3) |
|
1180 { |
|
1181 const TUint32 num = *reinterpret_cast<const TUint32*>(iReadBuf.Ptr()); |
|
1182 if (num != iPktNum) |
|
1183 { |
|
1184 TUSB_PRINT2("*** rcv'd wrong pkt number: 0x%x (expected: 0x%x)", num, iPktNum); |
|
1185 } |
|
1186 } |
|
1187 if (iBufSz == iMaxBufSz) |
|
1188 { |
|
1189 iBufSz = KInitialBufSz; |
|
1190 } |
|
1191 else |
|
1192 { |
|
1193 ++iBufSz; |
|
1194 } |
|
1195 SendPreamble(); // next we send the length |
|
1196 break; |
|
1197 default: |
|
1198 TUSB_PRINT("Oops. (Shouldn't end up here...)"); |
|
1199 break; |
|
1200 } |
|
1201 return; |
|
1202 } |
|
1203 |
|
1204 |
|
1205 TInt CActiveRW::SendVersion() |
|
1206 { |
|
1207 TUSB_VERBOSE_PRINT("CActiveRW::SendVersion()"); |
|
1208 if (iXferMode != ::ENone) |
|
1209 { |
|
1210 TUSB_PRINT1("Error : wrong state: %d", iXferMode); |
|
1211 return KErrGeneral; |
|
1212 } |
|
1213 // Here we send our version packet to the host. |
|
1214 // (We can use the preamble buffer because we only need it |
|
1215 // once and that's also before the preamble uses.) |
|
1216 TUSB_PRINT1("Sending T_USB version: %d\n", KTusbVersion); |
|
1217 iPreambleBuf.FillZ(); |
|
1218 *reinterpret_cast<TUint32*>(&iPreambleBuf[0]) = SWAP_BYTES_32(KTusbVersion); |
|
1219 // A 'magic' string so that USBRFLCT doesn't interpret the first 4 bytes |
|
1220 // of a data preamble packet of an old T_USB as the version number. |
|
1221 iPreambleBuf[4] = 'V'; |
|
1222 iPreambleBuf[5] = 'e'; |
|
1223 iPreambleBuf[6] = 'r'; |
|
1224 iPreambleBuf[7] = 's'; |
|
1225 TRequestStatus send_status; |
|
1226 iPort->Write(send_status, EEndpoint1, iPreambleBuf, KPreambleLength); |
|
1227 TUSB_VERBOSE_PRINT("Waiting for write request to complete..."); |
|
1228 User::WaitForRequest(send_status); |
|
1229 TUSB_VERBOSE_PRINT("...done.\n"); |
|
1230 return send_status.Int(); |
|
1231 } |
|
1232 |
|
1233 |
|
1234 TInt CActiveRW::ReceiveVersion() |
|
1235 { |
|
1236 TUSB_VERBOSE_PRINT("CActiveRW::ReceiveVersion()"); |
|
1237 if (iXferMode != ::ENone) |
|
1238 { |
|
1239 TUSB_PRINT1("Error : wrong state: %d", iXferMode); |
|
1240 return KErrGeneral; |
|
1241 } |
|
1242 // Here we try to receive a version packet from the host. |
|
1243 // (We can use the preamble buffer because we only need it |
|
1244 // once and that's also before the preamble uses.) |
|
1245 TUSB_PRINT("Getting host program versions..."); |
|
1246 iPreambleBuf.FillZ(); |
|
1247 TRequestStatus receive_status; |
|
1248 iPort->Read(receive_status, EEndpoint2, iPreambleBuf, KPreambleLength); |
|
1249 TUSB_VERBOSE_PRINT("Waiting for read request to complete..."); |
|
1250 iTimeoutTimer->Activate(5000000); // Host gets 5s |
|
1251 User::WaitForRequest(receive_status, iTimeoutTimer->iStatus); |
|
1252 if (receive_status == KRequestPending) |
|
1253 { |
|
1254 // Read() still pending... |
|
1255 TUSB_PRINT("Cancelling USB Read(): no response from host.\n"); |
|
1256 iPort->ReadCancel(EEndpoint2); |
|
1257 TUSB_PRINT("THIS COULD BE DUE TO AN OLD VERSION OF USBRFLCT ON THE PC:"); |
|
1258 TUSB_PRINT3("PLEASE CHECK THE VERSION THERE - WE NEED AT LEAST V%d.%d.%d!\n", |
|
1259 KUsbrflctVersionMajor, KUsbrflctVersionMinor, KUsbrflctVersionMicro); |
|
1260 TUSB_PRINT("When updating an existing USBRFLCT installation <= v1.3.1,\n" \ |
|
1261 L"the following three things will need to be done:\n"); |
|
1262 TUSB_PRINT("1. Connect the device to the PC & start T_USB (just as now),\n" \ |
|
1263 L"then find the USB device in the Windows Device Manager\n" \ |
|
1264 L"('Control Panel'->'System'->'Hardware'->'Device Manager').\n" \ |
|
1265 L"Right click on the device name and choose 'Uninstall...'.\n"); |
|
1266 TUSB_PRINT("2. In c:\\winnt\\inf\\, find (by searching for \"Symbian\") and\n" \ |
|
1267 L"delete the *.INF file that was used to install the existing\n" \ |
|
1268 L"version of USBRFLCT.SYS. Make sure to also delete the\n" \ |
|
1269 L"precompiled version of that file (<samename>.PNF).\n"); |
|
1270 TUSB_PRINT("3. In c:\\winnt\\system32\\drivers\\, delete the file USBRFLCT.SYS.\n"); |
|
1271 TUSB_PRINT("Then unplug & reconnect the USB device and, when prompted, install\n" \ |
|
1272 L"the new USBRFLCT.SYS driver using the .INF file from this distribution.\n" \ |
|
1273 L"(All files can be found under e32test\\win32\\usbrflct_distribution\\.)\n"); |
|
1274 TUSB_PRINT("Use the new USBRFLCT.EXE from this distribution.\n"); |
|
1275 } |
|
1276 else |
|
1277 { |
|
1278 TUSB_VERBOSE_PRINT("...done."); |
|
1279 // Timeout not needed any longer |
|
1280 TUSB_VERBOSE_PRINT("Cancelling timeout timer: USB Read() completed.\n"); |
|
1281 iTimeoutTimer->Cancel(); |
|
1282 } |
|
1283 return receive_status.Int(); |
|
1284 } |
|
1285 |
|
1286 |
|
1287 TInt CActiveRW::ExchangeVersions() |
|
1288 { |
|
1289 TUSB_VERBOSE_PRINT("CActiveRW::ExchangeVersions()"); |
|
1290 // First check the version of USBRFLCT that's running on the host |
|
1291 TInt r = ReceiveVersion(); |
|
1292 if (r != KErrNone) |
|
1293 { |
|
1294 return KErrGeneral; |
|
1295 } |
|
1296 TUint8 usbrflct_ver_major = iPreambleBuf[0]; |
|
1297 TUint8 usbrflct_ver_minor = iPreambleBuf[1]; |
|
1298 TUint8 usbrflct_ver_micro = iPreambleBuf[2]; |
|
1299 TUint8 usbio_ver_major = iPreambleBuf[3]; |
|
1300 TUint8 usbio_ver_minor = iPreambleBuf[4]; |
|
1301 TUSB_PRINT5("Host-side: USBRFLCT v%d.%d.%d USBIO v%d.%d\n", |
|
1302 usbrflct_ver_major, usbrflct_ver_minor, usbrflct_ver_micro, |
|
1303 usbio_ver_major, usbio_ver_minor); |
|
1304 if (usbrflct_ver_major < KUsbrflctVersionMajor) |
|
1305 { |
|
1306 TUSB_PRINT1("USBRFLCT version not sufficient (need at least v%d.x.x)\n", |
|
1307 KUsbrflctVersionMajor); |
|
1308 return KErrGeneral; |
|
1309 } |
|
1310 // Just using '<' instead of the seemingly absurd '<= && !==' doesn't work without |
|
1311 // GCC compiler warning because Kxxx can also be zero (in which case there's no '<'). |
|
1312 else if ((usbrflct_ver_minor <= KUsbrflctVersionMinor) && |
|
1313 !(usbrflct_ver_minor == KUsbrflctVersionMinor)) |
|
1314 { |
|
1315 TUSB_PRINT2("USBRFLCT version not sufficient (need at least v%d.%d.x)\n", |
|
1316 KUsbrflctVersionMajor, KUsbrflctVersionMinor); |
|
1317 return KErrGeneral; |
|
1318 } |
|
1319 // Just using '<' instead of the seemingly absurd '<= && !==' doesn't work without |
|
1320 // GCC compiler warning because Kxxx can also be zero (in which case there's no '<'). |
|
1321 else if ((usbrflct_ver_micro <= KUsbrflctVersionMicro) && |
|
1322 !(usbrflct_ver_micro == KUsbrflctVersionMicro)) |
|
1323 { |
|
1324 TUSB_PRINT3("USBRFLCT version not sufficient (need at least v%d.%d.%d)\n", |
|
1325 KUsbrflctVersionMajor, KUsbrflctVersionMinor, KUsbrflctVersionMicro); |
|
1326 return KErrGeneral; |
|
1327 } |
|
1328 // Now we send T_USB's version to the host |
|
1329 r = SendVersion(); |
|
1330 if (r != KErrNone) |
|
1331 { |
|
1332 return KErrGeneral; |
|
1333 } |
|
1334 return KErrNone; |
|
1335 } |
|
1336 |
|
1337 |
|
1338 void CActiveRW::SendPreamble() |
|
1339 { |
|
1340 TUSB_VERBOSE_PRINT("CActiveRW::SendPreamble()"); |
|
1341 __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666)); |
|
1342 TUSB_VERBOSE_PRINT1("Sending data length: %d bytes", iBufSz); |
|
1343 *reinterpret_cast<TUint32*>(&iPreambleBuf[0]) = SWAP_BYTES_32(iBufSz); |
|
1344 iPort->Write(iStatus, EEndpoint1, iPreambleBuf, KPreambleLength); |
|
1345 iCurrentXfer = EPreamble; |
|
1346 SetActive(); |
|
1347 } |
|
1348 |
|
1349 |
|
1350 void CActiveRW::SendData() |
|
1351 { |
|
1352 TUSB_VERBOSE_PRINT("CActiveRW::SendData()"); |
|
1353 __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666)); |
|
1354 if (iDiskAccessEnabled) |
|
1355 { |
|
1356 ReadBufferFromDisk(iWriteBuf, iBufSz); |
|
1357 } |
|
1358 ++iPktNum; |
|
1359 if (iBufSz > 3) |
|
1360 { |
|
1361 *reinterpret_cast<TUint32*>(const_cast<TUint8*>(iWriteBuf.Ptr())) = iPktNum; |
|
1362 } |
|
1363 if (iXferMode == ELoopComp) |
|
1364 { |
|
1365 for (TInt i = 4; i < iBufSz; i++) |
|
1366 { |
|
1367 iWriteBuf[i] = static_cast<TUint8>(iPktNum & 0x000000ff); |
|
1368 } |
|
1369 } |
|
1370 TUSB_VERBOSE_PRINT1("Sending data: %d bytes", iBufSz); |
|
1371 iPort->Write(iStatus, EEndpoint1, iWriteBuf, iBufSz); |
|
1372 iCurrentXfer = EWriteXfer; |
|
1373 SetActive(); |
|
1374 } |
|
1375 |
|
1376 |
|
1377 TInt CActiveRW::SelectDrive() |
|
1378 { |
|
1379 TDriveList driveList; |
|
1380 TInt r = iFs.DriveList(driveList); |
|
1381 if (r != KErrNone) |
|
1382 { |
|
1383 TUSB_PRINT1("RFs::DriveList() returned %d", r); |
|
1384 return r; |
|
1385 } |
|
1386 TUSB_PRINT("Available drives:"); |
|
1387 for (TInt n = 0; n < KMaxDrives; n++) |
|
1388 { |
|
1389 if (driveList[n] != 0) |
|
1390 { |
|
1391 TVolumeInfo volumeInfo; |
|
1392 r = iFs.Volume(volumeInfo, n); |
|
1393 if (r == KErrNone) |
|
1394 { |
|
1395 TPtr name(volumeInfo.iName.Des()); |
|
1396 TUSB_PRINT2("Drive %c: %- 16S", 'A' + n, &name); |
|
1397 if (volumeInfo.iDrive.iMediaAtt & KMediaAttWriteProtected) |
|
1398 TUSB_PRINT(" (read-only)"); |
|
1399 TUSB_PRINT(""); |
|
1400 } |
|
1401 } |
|
1402 } |
|
1403 iConsole->Printf(_L("Please select a drive letter (or 'Q' to quit)...")); |
|
1404 TChar driveLetter; |
|
1405 TInt driveNumber; |
|
1406 TVolumeInfo volumeInfo; |
|
1407 do |
|
1408 { |
|
1409 driveLetter = (TUint)iConsole->Getch(); |
|
1410 driveLetter.UpperCase(); |
|
1411 if (driveLetter == 'Q') |
|
1412 { |
|
1413 return KErrCancel; |
|
1414 } |
|
1415 driveNumber = (TUint)driveLetter - 'A'; |
|
1416 r = iFs.Volume(volumeInfo, driveNumber); |
|
1417 } |
|
1418 while ((driveNumber < 0) || |
|
1419 (driveNumber >= KMaxDrives) || |
|
1420 (r) || |
|
1421 (driveList[driveNumber] == 0) || |
|
1422 (volumeInfo.iDrive.iMediaAtt & KMediaAttWriteProtected)); |
|
1423 |
|
1424 iFileName.Format(_L("%c:"), driveLetter.operator TUint()); |
|
1425 iFileName.Append(KFileName); |
|
1426 TUSB_PRINT1("\nFilename = %S", &iFileName); |
|
1427 TUSB_PRINT1("File size: %d", KMaxFileSize); |
|
1428 return r; |
|
1429 } |
|
1430 |
|
1431 |
|
1432 TInt CActiveRW::WriteToDisk(TBool aEnable) |
|
1433 { |
|
1434 iDiskAccessEnabled = aEnable; |
|
1435 TInt r = KErrNone; |
|
1436 |
|
1437 if (iDiskAccessEnabled) |
|
1438 { |
|
1439 r = SelectDrive(); |
|
1440 if (r != KErrNone) |
|
1441 { |
|
1442 iDiskAccessEnabled = EFalse; |
|
1443 return r; |
|
1444 } |
|
1445 // open the record file |
|
1446 r = iFile.Replace(iFs, iFileName, EFileWrite); |
|
1447 iFileOffset = 0; |
|
1448 } |
|
1449 return r; |
|
1450 } |
|
1451 |
|
1452 |
|
1453 TInt CActiveRW::ReadFromDisk(TBool aEnable) |
|
1454 { |
|
1455 iDiskAccessEnabled = aEnable; |
|
1456 TInt r = KErrNone; |
|
1457 |
|
1458 if (iDiskAccessEnabled) |
|
1459 { |
|
1460 r = SelectDrive(); |
|
1461 if (r != KErrNone) |
|
1462 { |
|
1463 iDiskAccessEnabled = EFalse; |
|
1464 return r; |
|
1465 } |
|
1466 // First create the file & fill it |
|
1467 r = iFile.Replace(iFs, iFileName, EFileWrite); |
|
1468 if (r != KErrNone) |
|
1469 { |
|
1470 TUSB_PRINT1("RFile::Replace() returned %d", r); |
|
1471 iDiskAccessEnabled = EFalse; |
|
1472 return r; |
|
1473 } |
|
1474 const TInt KBufferSize = 4 * 1024; |
|
1475 TBuf8<KBufferSize> buffer; |
|
1476 buffer.SetLength(KBufferSize); |
|
1477 for (TInt n = 0; n < KBufferSize; n++) |
|
1478 { |
|
1479 buffer[n] = static_cast<TUint8>(n & 0x000000ff); |
|
1480 } |
|
1481 TUSB_PRINT("Writing data to file (this may take some minutes...)"); |
|
1482 for (TInt n = 0; n < KMaxFileSize; n += KBufferSize) |
|
1483 { |
|
1484 r = iFile.Write(buffer, KBufferSize); |
|
1485 if (r != KErrNone) |
|
1486 { |
|
1487 TUSB_PRINT1("RFile::Write() returned %d (disk full?)", r); |
|
1488 iFile.Close(); |
|
1489 iDiskAccessEnabled = EFalse; |
|
1490 return r; |
|
1491 } |
|
1492 } |
|
1493 TUSB_PRINT("Done."); |
|
1494 iFile.Close(); |
|
1495 // Now open the file for reading |
|
1496 r = iFile.Open(iFs, iFileName, EFileRead); |
|
1497 if (r != KErrNone) |
|
1498 { |
|
1499 TUSB_PRINT1("RFile::Open() returned %d", r); |
|
1500 iDiskAccessEnabled = EFalse; |
|
1501 return r; |
|
1502 } |
|
1503 iFileOffset = 0; |
|
1504 } |
|
1505 return r; |
|
1506 } |
|
1507 |
|
1508 |
|
1509 void CActiveRW::WriteBufferToDisk(TDes8& aBuffer, TInt aLen) |
|
1510 { |
|
1511 TUSB_VERBOSE_PRINT1("CActiveRW::WriteBufferToDisk(), len = %d", aLen); |
|
1512 TInt r = iFile.Write(aBuffer, aLen); |
|
1513 if (r != KErrNone) |
|
1514 { |
|
1515 TUSB_PRINT2("Error writing to %S (%d)", &iFileName, r); |
|
1516 iDiskAccessEnabled = EFalse; |
|
1517 return; |
|
1518 } |
|
1519 iFileOffset += aLen; |
|
1520 if (iFileOffset >= KMaxFileSize) |
|
1521 { |
|
1522 iFileOffset = 0; |
|
1523 iFile.Seek(ESeekStart, iFileOffset); |
|
1524 } |
|
1525 } |
|
1526 |
|
1527 |
|
1528 void CActiveRW::ReadBufferFromDisk(TDes8& aBuffer, TInt aLen) |
|
1529 { |
|
1530 if (iFileOffset + aLen >= KMaxFileSize) |
|
1531 { |
|
1532 iFileOffset = 0; |
|
1533 iFile.Seek(ESeekStart, iFileOffset); |
|
1534 } |
|
1535 const TInt r = iFile.Read(aBuffer, aLen); |
|
1536 if (r != KErrNone) |
|
1537 { |
|
1538 TUSB_PRINT2("Error reading from %S (%d)", &iFileName, r); |
|
1539 iDiskAccessEnabled = EFalse; |
|
1540 return; |
|
1541 } |
|
1542 TInt readLen = aBuffer.Length(); |
|
1543 TUSB_VERBOSE_PRINT1("CActiveRW::ReadBufferFromDisk(), len = %d\n", readLen); |
|
1544 if (readLen < aLen) |
|
1545 { |
|
1546 TUSB_PRINT3("Only %d bytes of %d read from file %S)", |
|
1547 readLen, aLen, &iFileName); |
|
1548 iDiskAccessEnabled = EFalse; |
|
1549 return; |
|
1550 } |
|
1551 iFileOffset += aLen; |
|
1552 } |
|
1553 |
|
1554 |
|
1555 void CActiveRW::ReadData() |
|
1556 { |
|
1557 TUSB_VERBOSE_PRINT("CActiveRW::ReadData()"); |
|
1558 __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666)); |
|
1559 TUSB_VERBOSE_PRINT1("Reading data: %d bytes", iBufSz); |
|
1560 if (iXferMode == EReceiveOnly) |
|
1561 { |
|
1562 TUSB_VERBOSE_PRINT(" (rx only)"); |
|
1563 iPort->Read(iStatus, EEndpoint2, iReadBuf, iBufSz); |
|
1564 } |
|
1565 else if (iBufSz == iMaxPktSz) |
|
1566 { |
|
1567 // we also want to test the packet version of Read() |
|
1568 TUSB_VERBOSE_PRINT(" (a single packet)"); |
|
1569 iPort->ReadPacket(iStatus, EEndpoint2, iReadBuf, iBufSz); |
|
1570 } |
|
1571 else if (iBufSz == iReadBuf.MaxSize()) |
|
1572 { |
|
1573 // or we could perhaps test the three-parameter version |
|
1574 TUSB_VERBOSE_PRINT(" (w/o length)"); |
|
1575 iPort->Read(iStatus, EEndpoint2, iReadBuf); |
|
1576 } |
|
1577 else |
|
1578 { |
|
1579 // otherwise, we use the universal default version |
|
1580 TUSB_VERBOSE_PRINT(" (normal)"); |
|
1581 iPort->Read(iStatus, EEndpoint2, iReadBuf, iBufSz); |
|
1582 } |
|
1583 iCurrentXfer = EReadXfer; |
|
1584 SetActive(); |
|
1585 } |
|
1586 |
|
1587 |
|
1588 void CActiveRW::Stop() |
|
1589 { |
|
1590 if (!IsActive()) |
|
1591 { |
|
1592 TUSB_PRINT("CActiveRW::Stop(): Not active"); |
|
1593 return; |
|
1594 } |
|
1595 TUSB_PRINT("Cancelling outstanding transfer requests\n"); |
|
1596 iBufSz = KInitialBufSz; |
|
1597 iPktNum = ~0; |
|
1598 iDoStop = ETrue; |
|
1599 iCurrentXfer = ENone; |
|
1600 Cancel(); |
|
1601 } |
|
1602 |
|
1603 |
|
1604 void CActiveRW::DoCancel() |
|
1605 { |
|
1606 TUSB_VERBOSE_PRINT("CActiveRW::DoCancel()"); |
|
1607 // Canceling the transfer requests can be done explicitly |
|
1608 // for every transfer... |
|
1609 iPort->WriteCancel(EEndpoint1); |
|
1610 iPort->ReadCancel(EEndpoint2); |
|
1611 // or like this: |
|
1612 iPort->EndpointTransferCancel(~0); |
|
1613 } |
|
1614 |
|
1615 |
|
1616 TBool CActiveRW::CompareBuffers(TInt aLen) |
|
1617 { |
|
1618 TUSB_VERBOSE_PRINT1("CActiveRW::CompareBuffers(%d)", aLen); |
|
1619 for (TInt i = 0; i < aLen; i++) |
|
1620 { |
|
1621 if (iReadBuf[i] != iWriteBuf[i]) |
|
1622 { |
|
1623 TUSB_VERBOSE_PRINT1("Error: for i = %d:", i); |
|
1624 TUSB_VERBOSE_PRINT2("iReadBuf: %d != iWriteBuf: %d", |
|
1625 iReadBuf[i], iWriteBuf[i]); |
|
1626 return EFalse; |
|
1627 } |
|
1628 } |
|
1629 return ETrue; |
|
1630 } |
|
1631 |
|
1632 |
|
1633 // |
|
1634 // --- class CActiveStallNotifier --------------------------------------------------------- |
|
1635 // |
|
1636 |
|
1637 CActiveStallNotifier::CActiveStallNotifier(CConsoleBase* aConsole, RDevUsbcClient* aPort, |
|
1638 TBool aVerboseOutput) |
|
1639 : CActive(EPriorityNormal), |
|
1640 iConsole(aConsole), |
|
1641 iPort(aPort), |
|
1642 iEndpointState(0), |
|
1643 iVerbose(aVerboseOutput) |
|
1644 { |
|
1645 CActiveScheduler::Add(this); |
|
1646 } |
|
1647 |
|
1648 CActiveStallNotifier* CActiveStallNotifier::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort, |
|
1649 TBool aVerboseOutput) |
|
1650 { |
|
1651 CActiveStallNotifier* self = new (ELeave) CActiveStallNotifier(aConsole, aPort, aVerboseOutput); |
|
1652 CleanupStack::PushL(self); |
|
1653 self->ConstructL(); |
|
1654 CleanupStack::Pop(); // self |
|
1655 return self; |
|
1656 } |
|
1657 |
|
1658 |
|
1659 void CActiveStallNotifier::ConstructL() |
|
1660 {} |
|
1661 |
|
1662 |
|
1663 CActiveStallNotifier::~CActiveStallNotifier() |
|
1664 { |
|
1665 TUSB_VERBOSE_PRINT("CActiveStallNotifier::~CActiveStallNotifier()"); |
|
1666 Cancel(); // base class |
|
1667 } |
|
1668 |
|
1669 |
|
1670 void CActiveStallNotifier::DoCancel() |
|
1671 { |
|
1672 TUSB_VERBOSE_PRINT("CActiveStallNotifier::DoCancel()"); |
|
1673 iPort->EndpointStatusNotifyCancel(); |
|
1674 } |
|
1675 |
|
1676 |
|
1677 void CActiveStallNotifier::RunL() |
|
1678 { |
|
1679 // This just displays the bitmap, showing which endpoints (if any) are now stalled. |
|
1680 // In a real world program, the user could take here appropriate action (cancel a |
|
1681 // transfer request or whatever). |
|
1682 TUSB_VERBOSE_PRINT1("StallNotifier: Endpointstate 0x%x\n", iEndpointState); |
|
1683 Activate(); |
|
1684 } |
|
1685 |
|
1686 |
|
1687 void CActiveStallNotifier::Activate() |
|
1688 { |
|
1689 __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666)); |
|
1690 iPort->EndpointStatusNotify(iStatus, iEndpointState); |
|
1691 SetActive(); |
|
1692 } |
|
1693 |
|
1694 |
|
1695 // |
|
1696 // --- class CActiveDeviceStateNotifier --------------------------------------------------------- |
|
1697 // |
|
1698 |
|
1699 CActiveDeviceStateNotifier::CActiveDeviceStateNotifier(CConsoleBase* aConsole, RDevUsbcClient* aPort, |
|
1700 TBool aVerboseOutput) |
|
1701 : CActive(EPriorityNormal), |
|
1702 iConsole(aConsole), |
|
1703 iPort(aPort), |
|
1704 iDeviceState(0), |
|
1705 iVerbose(aVerboseOutput) |
|
1706 { |
|
1707 CActiveScheduler::Add(this); |
|
1708 } |
|
1709 |
|
1710 CActiveDeviceStateNotifier* CActiveDeviceStateNotifier::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort, |
|
1711 TBool aVerboseOutput) |
|
1712 { |
|
1713 CActiveDeviceStateNotifier* self = new (ELeave) CActiveDeviceStateNotifier(aConsole, aPort, aVerboseOutput); |
|
1714 CleanupStack::PushL(self); |
|
1715 self->ConstructL(); |
|
1716 CleanupStack::Pop(); // self |
|
1717 return self; |
|
1718 } |
|
1719 |
|
1720 |
|
1721 void CActiveDeviceStateNotifier::ConstructL() |
|
1722 {} |
|
1723 |
|
1724 |
|
1725 CActiveDeviceStateNotifier::~CActiveDeviceStateNotifier() |
|
1726 { |
|
1727 TUSB_VERBOSE_PRINT("CActiveDeviceStateNotifier::~CActiveDeviceStateNotifier()"); |
|
1728 Cancel(); // base class |
|
1729 } |
|
1730 |
|
1731 |
|
1732 void CActiveDeviceStateNotifier::DoCancel() |
|
1733 { |
|
1734 TUSB_VERBOSE_PRINT("CActiveDeviceStateNotifier::DoCancel()"); |
|
1735 iPort->AlternateDeviceStatusNotifyCancel(); |
|
1736 } |
|
1737 |
|
1738 |
|
1739 void CActiveDeviceStateNotifier::RunL() |
|
1740 { |
|
1741 // This displays the device state. |
|
1742 // In a real world program, the user could take here appropriate action (cancel a |
|
1743 // transfer request or whatever). |
|
1744 if (!(iDeviceState & KUsbAlternateSetting) && iVerbose) |
|
1745 { |
|
1746 switch (iDeviceState) |
|
1747 { |
|
1748 case EUsbcDeviceStateUndefined: |
|
1749 TUSB_PRINT("Device State notifier: Undefined"); |
|
1750 break; |
|
1751 case EUsbcDeviceStateAttached: |
|
1752 TUSB_PRINT("Device State notifier: Attached"); |
|
1753 break; |
|
1754 case EUsbcDeviceStatePowered: |
|
1755 TUSB_PRINT("Device State notifier: Powered"); |
|
1756 break; |
|
1757 case EUsbcDeviceStateDefault: |
|
1758 TUSB_PRINT("Device State notifier: Default"); |
|
1759 break; |
|
1760 case EUsbcDeviceStateAddress: |
|
1761 TUSB_PRINT("Device State notifier: Address"); |
|
1762 break; |
|
1763 case EUsbcDeviceStateConfigured: |
|
1764 TUSB_PRINT("Device State notifier: Configured"); |
|
1765 break; |
|
1766 case EUsbcDeviceStateSuspended: |
|
1767 TUSB_PRINT("Device State notifier: Suspended"); |
|
1768 break; |
|
1769 default: |
|
1770 TUSB_PRINT("Device State notifier: ***BAD***"); |
|
1771 } |
|
1772 } |
|
1773 else if (iDeviceState & KUsbAlternateSetting) |
|
1774 { |
|
1775 TUSB_PRINT1("Device State notifier: Alternate interface setting has changed: now %d", |
|
1776 iDeviceState & ~KUsbAlternateSetting); |
|
1777 } |
|
1778 Activate(); |
|
1779 } |
|
1780 |
|
1781 |
|
1782 void CActiveDeviceStateNotifier::Activate() |
|
1783 { |
|
1784 __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666)); |
|
1785 iPort->AlternateDeviceStatusNotify(iStatus, iDeviceState); |
|
1786 SetActive(); |
|
1787 } |
|
1788 |
|
1789 |
|
1790 // |
|
1791 // --- class CActiveTimer --------------------------------------------------------- |
|
1792 // |
|
1793 |
|
1794 CActiveTimer::CActiveTimer(CConsoleBase* aConsole, RDevUsbcClient* aPort, |
|
1795 TBool aVerboseOutput) |
|
1796 : CActive(EPriorityNormal), |
|
1797 iConsole(aConsole), |
|
1798 iPort(aPort), |
|
1799 iVerbose(aVerboseOutput) |
|
1800 { |
|
1801 CActiveScheduler::Add(this); |
|
1802 } |
|
1803 |
|
1804 |
|
1805 CActiveTimer* CActiveTimer::NewL(CConsoleBase* aConsole, RDevUsbcClient* aPort, |
|
1806 TBool aVerboseOutput) |
|
1807 { |
|
1808 CActiveTimer* self = new (ELeave) CActiveTimer(aConsole, aPort, aVerboseOutput); |
|
1809 CleanupStack::PushL(self); |
|
1810 self->ConstructL(); |
|
1811 CleanupStack::Pop(); // self |
|
1812 return self; |
|
1813 } |
|
1814 |
|
1815 |
|
1816 void CActiveTimer::ConstructL() |
|
1817 { |
|
1818 User::LeaveIfError(iTimer.CreateLocal()); |
|
1819 } |
|
1820 |
|
1821 |
|
1822 CActiveTimer::~CActiveTimer() |
|
1823 { |
|
1824 TUSB_VERBOSE_PRINT("CActiveTimer::~CActiveTimer()"); |
|
1825 Cancel(); // base class |
|
1826 iTimer.Close(); |
|
1827 } |
|
1828 |
|
1829 |
|
1830 void CActiveTimer::DoCancel() |
|
1831 { |
|
1832 TUSB_VERBOSE_PRINT("CActiveTimer::DoCancel()"); |
|
1833 iTimer.Cancel(); |
|
1834 } |
|
1835 |
|
1836 |
|
1837 void CActiveTimer::RunL() |
|
1838 { |
|
1839 TUSB_VERBOSE_PRINT("CActiveTimer::RunL()"); |
|
1840 // Nothing to do here, as we call ReadCancel() after a manual WaitForRequest() |
|
1841 // (in CActiveRW::ReceiveVersion()). |
|
1842 } |
|
1843 |
|
1844 |
|
1845 void CActiveTimer::Activate(TTimeIntervalMicroSeconds32 aDelay) |
|
1846 { |
|
1847 __ASSERT_ALWAYS(!IsActive(), User::Panic(KActivePanic, 666)); |
|
1848 iTimer.After(iStatus, aDelay); |
|
1849 SetActive(); |
|
1850 } |
|
1851 |
|
1852 |
|
1853 // -eof- |