902afd0297d049b29f56c6d27ec08d21eb44fa46
[reactos.git] / drivers / net / packet / openclos.c
1 /*
2  * Copyright (c) 1999, 2000
3  *      Politecnico di Torino.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that: (1) source code distributions
7  * retain the above copyright notice and this paragraph in its entirety, (2)
8  * distributions including binary code include the above copyright notice and
9  * this paragraph in its entirety in the documentation or other materials
10  * provided with the distribution, and (3) all advertising materials mentioning
11  * features or use of this software display the following acknowledgement:
12  * ``This product includes software developed by the Politecnico
13  * di Torino, and its contributors.'' Neither the name of
14  * the University nor the names of its contributors may be used to endorse
15  * or promote products derived from this software without specific prior
16  * written permission.
17  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
18  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20  */
21
22 #ifdef _MSC_VER
23 #include "ntddk.h"
24 #include "ntiologc.h"
25 #include "ndis.h"
26 #else
27 #include <ddk/ntddk.h>
28 #include <net/ndis.h>
29 #endif
30 #include "debug.h"
31 #include "packet.h"
32
33 static NDIS_MEDIUM MediumArray[] = {
34         NdisMedium802_3,
35         NdisMediumWan,
36         NdisMediumFddi,
37         NdisMediumArcnet878_2,
38         NdisMediumAtm,
39         NdisMedium802_5
40 };
41
42 #define NUM_NDIS_MEDIA  (sizeof MediumArray / sizeof MediumArray[0])
43
44 ULONG NamedEventsCounter=0;
45
46 //Itoa. Replaces the buggy RtlIntegerToUnicodeString
47 void PacketItoa(UINT n,PUCHAR buf){
48 int i;
49
50         for(i=0;i<20;i+=2){
51                 buf[18-i]=(n%10)+48;
52                 buf[19-i]=0;
53                 n/=10;
54         }
55
56 }
57
58 /// Global start time. Used as an absolute reference for timestamp conversion.
59 struct time_conv G_Start_Time = {
60         0,      
61         {0, 0}, 
62 };
63
64 UINT n_Opened_Instances = 0;
65
66 NDIS_SPIN_LOCK Opened_Instances_Lock;
67
68 //-------------------------------------------------------------------
69
70 NTSTATUS NPF_Open(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
71 {
72
73     PDEVICE_EXTENSION DeviceExtension;
74
75     POPEN_INSTANCE    Open;
76
77     PIO_STACK_LOCATION  IrpSp;
78
79     NDIS_STATUS     Status;
80     NDIS_STATUS     ErrorStatus;
81     UINT            i;
82         PUCHAR                  tpointer;
83     PLIST_ENTRY     PacketListEntry;
84         PCHAR                   EvName;
85
86     IF_LOUD(DbgPrint("NPF: OpenAdapter\n");)
87
88     DeviceExtension = DeviceObject->DeviceExtension;
89
90
91     IrpSp = IoGetCurrentIrpStackLocation(Irp);
92
93     //  allocate some memory for the open structure
94 #define NPF_TAG_OPENSTRUCT  TAG('0', 'O', 'W', 'A')
95     Open=ExAllocatePoolWithTag(NonPagedPool, sizeof(OPEN_INSTANCE), NPF_TAG_OPENSTRUCT);
96
97
98     if (Open==NULL) {
99         // no memory
100         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
101         IoCompleteRequest(Irp, IO_NO_INCREMENT);
102         return STATUS_INSUFFICIENT_RESOURCES;
103     }
104
105     RtlZeroMemory(
106         Open,
107         sizeof(OPEN_INSTANCE)
108         );
109
110
111 #define NPF_TAG_EVNAME  TAG('1', 'O', 'W', 'A')
112         EvName=ExAllocatePoolWithTag(NonPagedPool, sizeof(L"\\BaseNamedObjects\\NPF0000000000"), NPF_TAG_EVNAME);
113
114     if (EvName==NULL) {
115         // no memory
116         ExFreePool(Open);
117             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
118         IoCompleteRequest(Irp, IO_NO_INCREMENT);
119         return STATUS_INSUFFICIENT_RESOURCES;
120     }
121
122     //  Save or open here
123     IrpSp->FileObject->FsContext=Open;
124         
125     Open->DeviceExtension=DeviceExtension;
126         
127         
128     //  Save the Irp here for the completeion routine to retrieve
129     Open->OpenCloseIrp=Irp;
130         
131     //  Allocate a packet pool for our xmit and receive packets
132     NdisAllocatePacketPool(
133         &Status,
134         &Open->PacketPool,
135         TRANSMIT_PACKETS,
136         sizeof(PACKET_RESERVED));
137         
138         
139     if (Status != NDIS_STATUS_SUCCESS) {
140                 
141         IF_LOUD(DbgPrint("NPF: Failed to allocate packet pool\n");)
142                         
143                 ExFreePool(Open);
144                 ExFreePool(EvName);
145         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
146         IoCompleteRequest(Irp, IO_NO_INCREMENT);
147         return STATUS_INSUFFICIENT_RESOURCES;
148     }
149
150
151         RtlCopyBytes(EvName,L"\\BaseNamedObjects\\NPF0000000000",sizeof(L"\\BaseNamedObjects\\NPF0000000000"));
152
153         //Create the string containing the name of the read event
154         RtlInitUnicodeString(&Open->ReadEventName,(PCWSTR) EvName);
155
156         PacketItoa(NamedEventsCounter,(PUCHAR)(Open->ReadEventName.Buffer+21));
157
158         InterlockedIncrement(&NamedEventsCounter);
159         
160         IF_LOUD(DbgPrint("\nCreated the named event for the read; name=%ws, counter=%d\n", Open->ReadEventName.Buffer,NamedEventsCounter-1);)
161
162         //allocate the event objects
163         Open->ReadEvent=IoCreateNotificationEvent(&Open->ReadEventName,&Open->ReadEventHandle);
164         if(Open->ReadEvent==NULL){
165                 ExFreePool(Open);
166                 ExFreePool(EvName);
167         Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
168         IoCompleteRequest(Irp, IO_NO_INCREMENT);
169         return STATUS_INSUFFICIENT_RESOURCES;
170         }
171         
172         KeInitializeEvent(Open->ReadEvent, NotificationEvent, FALSE);
173         KeClearEvent(Open->ReadEvent);
174         NdisInitializeEvent(&Open->WriteEvent);
175         NdisInitializeEvent(&Open->IOEvent);
176         NdisInitializeEvent(&Open->DumpEvent);
177         NdisInitializeEvent(&Open->IOEvent);
178         NdisAllocateSpinLock(&Open->machine_lock);
179
180
181     //  list to hold irp's want to reset the adapter
182     InitializeListHead(&Open->ResetIrpList);
183         
184         
185     //  Initialize the request list
186     KeInitializeSpinLock(&Open->RequestSpinLock);
187     InitializeListHead(&Open->RequestList);
188
189         // Initializes the extended memory of the NPF machine
190 #define NPF_TAG_MACHINE  TAG('2', 'O', 'W', 'A')
191         Open->mem_ex.buffer = ExAllocatePoolWithTag(NonPagedPool, DEFAULT_MEM_EX_SIZE, NPF_TAG_MACHINE);
192         if((Open->mem_ex.buffer) == NULL)
193         {
194         // no memory
195         ExFreePool(Open);
196                 ExFreePool(EvName);
197             Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
198         IoCompleteRequest(Irp, IO_NO_INCREMENT);
199         return STATUS_INSUFFICIENT_RESOURCES;
200     }
201         
202         Open->mem_ex.size = DEFAULT_MEM_EX_SIZE;
203         RtlZeroMemory(Open->mem_ex.buffer, DEFAULT_MEM_EX_SIZE);
204         
205         //
206         // Initialize the open instance
207         //
208         Open->BufSize = 0;
209         Open->Buffer = NULL;
210         Open->Bhead = 0;
211         Open->Btail = 0;
212         (INT)Open->BLastByte = -1;
213         Open->Dropped = 0;              //reset the dropped packets counter
214         Open->Received = 0;             //reset the received packets counter
215         Open->Accepted = 0;             //reset the accepted packets counter
216         Open->bpfprogram = NULL;        //reset the filter
217         Open->mode = MODE_CAPT;
218         Open->Nbytes.QuadPart = 0;
219         Open->Npackets.QuadPart = 0;
220         Open->Nwrites = 1;
221         Open->Multiple_Write_Counter = 0;
222         Open->MinToCopy = 0;
223         Open->TimeOut.QuadPart = (LONGLONG)1;
224         Open->Bound = TRUE;
225         Open->DumpFileName.Buffer = NULL;
226         Open->DumpFileHandle = NULL;
227         Open->tme.active = TME_NONE_ACTIVE;
228         Open->DumpLimitReached = FALSE;
229         Open->MaxFrameSize = 0;
230
231         //allocate the spinlock for the statistic counters
232     NdisAllocateSpinLock(&Open->CountersLock);
233
234         //allocate the spinlock for the buffer pointers
235     NdisAllocateSpinLock(&Open->BufLock);
236         
237     //
238     //  link up the request stored in our open block
239     //
240     for (i=0;i<MAX_REQUESTS;i++) {
241         ExInterlockedInsertTailList(
242             &Open->RequestList,
243             &Open->Requests[i].ListElement,
244             &Open->RequestSpinLock);
245                 
246     }
247         
248
249     IoMarkIrpPending(Irp);
250         
251     //
252     //  Try to open the MAC
253     //
254     IF_LOUD(DbgPrint("NPF: Openinig the device %ws, BindingContext=%d\n",DeviceExtension->AdapterName.Buffer, Open);)
255
256         NdisOpenAdapter(
257         &Status,
258         &ErrorStatus,
259         &Open->AdapterHandle,
260         &Open->Medium,
261         MediumArray,
262         NUM_NDIS_MEDIA,
263         DeviceExtension->NdisProtocolHandle,
264         Open,
265         &DeviceExtension->AdapterName,
266         0,
267         NULL);
268
269     IF_LOUD(DbgPrint("NPF: Opened the device, Status=%x\n",Status);)
270
271         if (Status != NDIS_STATUS_PENDING)
272     {
273                 NPF_OpenAdapterComplete(Open,Status,NDIS_STATUS_SUCCESS);
274     }
275         
276     return(STATUS_PENDING);
277 }
278
279 //-------------------------------------------------------------------
280
281 VOID NPF_OpenAdapterComplete(
282         IN NDIS_HANDLE  ProtocolBindingContext,
283     IN NDIS_STATUS  Status,
284     IN NDIS_STATUS  OpenErrorStatus)
285 {
286
287     PIRP                Irp;
288     POPEN_INSTANCE      Open;
289     PLIST_ENTRY                 RequestListEntry;
290         PINTERNAL_REQUEST       MaxSizeReq;
291         NDIS_STATUS                     ReqStatus;
292
293
294     IF_LOUD(DbgPrint("NPF: OpenAdapterComplete\n");)
295
296     Open= (POPEN_INSTANCE)ProtocolBindingContext;
297
298     //
299     //  get the open irp
300     //
301     Irp=Open->OpenCloseIrp;
302
303     if (Status != NDIS_STATUS_SUCCESS) {
304
305         IF_LOUD(DbgPrint("NPF: OpenAdapterComplete-FAILURE\n");)
306
307         NdisFreePacketPool(Open->PacketPool);
308
309                 //free mem_ex
310                 Open->mem_ex.size = 0;
311                 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
312
313                 ExFreePool(Open->ReadEventName.Buffer);
314
315                 ZwClose(Open->ReadEventHandle);
316
317
318         ExFreePool(Open);
319     }
320         else {
321                 NdisAcquireSpinLock(&Opened_Instances_Lock);
322                 n_Opened_Instances++;
323                 NdisReleaseSpinLock(&Opened_Instances_Lock);
324                 
325                 IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
326
327                 // Get the absolute value of the system boot time.
328                 // This is used for timestamp conversion.
329                 TIME_SYNCHRONIZE(&G_Start_Time);
330
331                 // Extract a request from the list of free ones
332                 RequestListEntry=ExInterlockedRemoveHeadList(&Open->RequestList, &Open->RequestSpinLock);
333
334                 if (RequestListEntry == NULL)
335                 {
336
337                     Open->MaxFrameSize = 1514;  // Assume Ethernet
338
339                         Irp->IoStatus.Status = Status;
340                     Irp->IoStatus.Information = 0;
341                     IoCompleteRequest(Irp, IO_NO_INCREMENT);
342
343                     return;
344                 }
345
346                 MaxSizeReq = CONTAINING_RECORD(RequestListEntry, INTERNAL_REQUEST, ListElement);
347                 MaxSizeReq->Irp = Irp;
348                 MaxSizeReq->Internal = TRUE;
349
350                 
351                 MaxSizeReq->Request.RequestType = NdisRequestQueryInformation;
352                 MaxSizeReq->Request.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE;
353
354                 
355                 MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBuffer = &Open->MaxFrameSize;
356                 MaxSizeReq->Request.DATA.QUERY_INFORMATION.InformationBufferLength = 4;
357
358                 //  submit the request
359                 NdisRequest(
360                         &ReqStatus,
361                         Open->AdapterHandle,
362                         &MaxSizeReq->Request);
363
364
365                 if (ReqStatus != NDIS_STATUS_PENDING) {
366                         NPF_RequestComplete(Open, &MaxSizeReq->Request, ReqStatus);
367                 }
368
369                 return;
370
371         }
372
373     Irp->IoStatus.Status = Status;
374     Irp->IoStatus.Information = 0;
375     IoCompleteRequest(Irp, IO_NO_INCREMENT);
376
377     return;
378
379 }
380
381 //-------------------------------------------------------------------
382
383 NTSTATUS
384 NPF_Close(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)
385 {
386
387     POPEN_INSTANCE    Open;
388     NDIS_STATUS     Status;
389     PIO_STACK_LOCATION  IrpSp;
390         LARGE_INTEGER ThreadDelay;
391
392     IF_LOUD(DbgPrint("NPF: CloseAdapter\n");)
393
394         IrpSp = IoGetCurrentIrpStackLocation(Irp);
395
396     Open=IrpSp->FileObject->FsContext;
397
398         // Reset the buffer size. This tells the dump thread to stop.
399         Open->BufSize = 0;
400
401         if( Open->Bound == FALSE){
402
403                 NdisWaitEvent(&Open->IOEvent,10000);
404
405                 // Free the filter if it's present
406                 if(Open->bpfprogram != NULL)
407                         ExFreePool(Open->bpfprogram);
408
409                 // Free the jitted filter if it's present
410                 if(Open->Filter != NULL)
411                         BPF_Destroy_JIT_Filter(Open->Filter);
412
413                 //free the buffer
414                 Open->BufSize=0;
415                 if(Open->Buffer != NULL)ExFreePool(Open->Buffer);
416                 
417                 //free mem_ex
418                 Open->mem_ex.size = 0;
419                 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
420                                 
421                 NdisFreePacketPool(Open->PacketPool);
422
423                 // Free the string with the name of the dump file
424                 if(Open->DumpFileName.Buffer!=NULL)
425                         ExFreePool(Open->DumpFileName.Buffer);
426                         
427                 ExFreePool(Open->ReadEventName.Buffer);
428                 ExFreePool(Open);
429
430                 Irp->IoStatus.Information = 0;
431                 Irp->IoStatus.Status = STATUS_SUCCESS;
432                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
433                 
434                 return(STATUS_SUCCESS);
435         }
436
437         // Unfreeze the consumer
438         if(Open->mode & MODE_DUMP)
439                 NdisSetEvent(&Open->DumpEvent);
440         else
441                 KeSetEvent(Open->ReadEvent,0,FALSE);
442
443     // Save the IRP
444     Open->OpenCloseIrp = Irp;
445
446     IoMarkIrpPending(Irp);
447  
448         // If this instance is in dump mode, complete the dump and close the file
449         if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL){
450                 NTSTATUS wres;
451
452                 ThreadDelay.QuadPart = -50000000;
453                 // Wait the completion of the thread
454                 wres = KeWaitForSingleObject(Open->DumpThreadObject,
455                                 UserRequest,
456                                 KernelMode,
457                                 TRUE,
458                                 &ThreadDelay);
459
460                 ObDereferenceObject(Open->DumpThreadObject);
461
462
463                 // Flush and close the dump file
464                 NPF_CloseDumpFile(Open);
465         }
466
467         // Destroy the read Event
468         ZwClose(Open->ReadEventHandle);
469
470         // Close the adapter
471         NdisCloseAdapter(
472                 &Status,
473                 Open->AdapterHandle
474                 );
475
476         if (Status != NDIS_STATUS_PENDING) {
477                 
478                 NPF_CloseAdapterComplete(
479                         Open,
480                         Status
481                         );
482                 return STATUS_SUCCESS;
483                 
484         }
485         
486         return(STATUS_PENDING);
487 }
488
489 //-------------------------------------------------------------------
490
491 VOID
492 NPF_CloseAdapterComplete(IN NDIS_HANDLE  ProtocolBindingContext,IN NDIS_STATUS  Status)
493 {
494     POPEN_INSTANCE    Open;
495     PIRP              Irp;
496
497     IF_LOUD(DbgPrint("NPF: CloseAdapterComplete\n");)
498
499     Open= (POPEN_INSTANCE)ProtocolBindingContext;
500
501         // free the allocated structures only if the instance is still bound to the adapter
502         if(Open->Bound == TRUE){
503                 
504                 // Free the filter if it's present
505                 if(Open->bpfprogram != NULL)
506                         ExFreePool(Open->bpfprogram);
507
508                 // Free the jitted filter if it's present
509                 if(Open->Filter != NULL)
510                         BPF_Destroy_JIT_Filter(Open->Filter);
511                 
512                 //free the buffer
513                 Open->BufSize = 0;
514                 if(Open->Buffer!=NULL)ExFreePool(Open->Buffer);
515                 
516                 //free mem_ex
517                 Open->mem_ex.size = 0;
518                 if(Open->mem_ex.buffer != NULL)ExFreePool(Open->mem_ex.buffer);
519                 
520                 NdisFreePacketPool(Open->PacketPool);
521                 
522                 Irp=Open->OpenCloseIrp;
523                 
524                 // Free the string with the name of the dump file
525                 if(Open->DumpFileName.Buffer!=NULL)
526                         ExFreePool(Open->DumpFileName.Buffer);
527
528                 ExFreePool(Open->ReadEventName.Buffer);
529                 ExFreePool(Open);
530                 
531                 // Complete the request only if the instance is still bound to the adapter
532                 Irp->IoStatus.Status = STATUS_SUCCESS;
533                 Irp->IoStatus.Information = 0;
534                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
535         }
536         else
537                 NdisSetEvent(&Open->IOEvent);
538
539         // Decrease the counter of open instances
540         NdisAcquireSpinLock(&Opened_Instances_Lock);
541         n_Opened_Instances--;
542         NdisReleaseSpinLock(&Opened_Instances_Lock);
543
544         IF_LOUD(DbgPrint("Opened Instances:%d", n_Opened_Instances);)
545
546         if(n_Opened_Instances == 0){
547                 // Force a synchronization at the next NPF_Open().
548                 // This hopefully avoids the synchronization issues caused by hibernation or standby.
549                 TIME_DESYNCHRONIZE(&G_Start_Time);
550         }
551
552         return;
553
554 }
555 //-------------------------------------------------------------------
556
557 #ifdef NDIS50
558 NDIS_STATUS
559 NPF_PowerChange(IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent)
560 {
561     IF_LOUD(DbgPrint("NPF: PowerChange\n");)
562
563         TIME_DESYNCHRONIZE(&G_Start_Time);
564
565         TIME_SYNCHRONIZE(&G_Start_Time);
566
567         return STATUS_SUCCESS;
568 }
569 #endif
570
571 //-------------------------------------------------------------------
572
573 VOID
574 NPF_BindAdapter(
575     OUT PNDIS_STATUS            Status,
576     IN  NDIS_HANDLE             BindContext,
577     IN  PNDIS_STRING            DeviceName,
578     IN  PVOID                   SystemSpecific1,
579     IN  PVOID                   SystemSpecific2
580     )
581 {
582         IF_LOUD(DbgPrint("NPF: NPF_BindAdapter\n");)
583 }
584
585 //-------------------------------------------------------------------
586
587 VOID
588 NPF_UnbindAdapter(
589     OUT PNDIS_STATUS        Status,
590     IN  NDIS_HANDLE         ProtocolBindingContext,
591     IN  NDIS_HANDLE         UnbindContext
592     )
593 {
594     POPEN_INSTANCE   Open =(POPEN_INSTANCE)ProtocolBindingContext;
595         NDIS_STATUS              lStatus;
596
597         IF_LOUD(DbgPrint("NPF: NPF_UnbindAdapter\n");)
598
599         // Reset the buffer size. This tells the dump thread to stop.
600         Open->BufSize=0;
601
602         NdisResetEvent(&Open->IOEvent);
603
604         // This open instance is no more bound to the adapter, set Bound to False
605     InterlockedExchange( (PLONG) &Open->Bound, FALSE );
606
607         // Awake a possible pending read on this instance
608         if(Open->mode & MODE_DUMP)
609                 NdisSetEvent(&Open->DumpEvent);
610         else
611                 KeSetEvent(Open->ReadEvent,0,FALSE);
612
613         // If this instance is in dump mode, complete the dump and close the file
614         if((Open->mode & MODE_DUMP) && Open->DumpFileHandle != NULL)
615                 NPF_CloseDumpFile(Open);
616
617         // Destroy the read Event
618         ZwClose(Open->ReadEventHandle);
619
620     //  close the adapter
621     NdisCloseAdapter(
622         &lStatus,
623         Open->AdapterHandle
624             );
625
626     if (lStatus != NDIS_STATUS_PENDING) {
627
628         NPF_CloseAdapterComplete(
629             Open,
630             lStatus
631             );
632
633                 *Status = NDIS_STATUS_SUCCESS;
634         return;
635
636     }
637
638         *Status = NDIS_STATUS_SUCCESS;
639     return;
640 }
641
642 //-------------------------------------------------------------------
643
644 VOID
645 NPF_ResetComplete(IN NDIS_HANDLE  ProtocolBindingContext,IN NDIS_STATUS  Status)
646
647 {
648     POPEN_INSTANCE      Open;
649     PIRP                Irp;
650
651     PLIST_ENTRY         ResetListEntry;
652
653     IF_LOUD(DbgPrint("NPF: PacketResetComplte\n");)
654
655     Open= (POPEN_INSTANCE)ProtocolBindingContext;
656
657
658     //
659     //  remove the reset IRP from the list
660     //
661     ResetListEntry=ExInterlockedRemoveHeadList(
662                        &Open->ResetIrpList,
663                        &Open->RequestSpinLock
664                        );
665
666 #if DBG
667     if (ResetListEntry == NULL) {
668         DbgBreakPoint();
669         return;
670     }
671 #endif
672
673     Irp=CONTAINING_RECORD(ResetListEntry,IRP,Tail.Overlay.ListEntry);
674
675     Irp->IoStatus.Status = STATUS_SUCCESS;
676     IoCompleteRequest(Irp, IO_NO_INCREMENT);
677
678     IF_LOUD(DbgPrint("NPF: PacketResetComplte exit\n");)
679
680     return;
681
682 }