forked from OS2World/UTIL-SYSTEM-HWMan
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhwman.cpp
1023 lines (896 loc) · 43 KB
/
hwman.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* This file was generated by the SOM Compiler.
* Generated using:
* SOM incremental update: 2.47
*/
/*
* This file was generated by the SOM Compiler and Emitter Framework.
* Generated using template emitter:
* SOM Emitter emitxtm: 2.23.1.9
*/
#ifndef SOM_Module_hwman_Source
#define SOM_Module_hwman_Source
#endif
#define WPHwManagerEx_Class_Source
#define M_WPHwManagerEx_Class_Source
#define _RETAIL /* to completely eliminate the ...MethodDebug(...) debugging output to SOMOutCharRoutine (default:stdout) */
#include "hwman.xih"
#include "devcpu.xih"
#include "datacls.xh"
#include "except.h"
#if (defined(__IBMC__) || defined(__IBMCPP__))
#include <umalloc.h>
#endif
#if defined(__WATCOMC__)
#include <malloc.h>
#endif
void APIENTRY cpuGetBrandString(PSZ buf,ULONG buflen);
somToken SOMLINK MyCalloc(size_t element_count,size_t element_size);
void SOMLINK MyFree(somToken memory);
somToken SOMLINK MyMalloc(size_t nbytes);
somToken SOMLINK MyRealloc(somToken memory,size_t nbytes);
// we replace the standard SOM memory management functions with our own
// this was done so that we can do all memory allocation in high memory
// we are using a private heap. This functionality is offered by the VAC
// RTL library by means of the _ucreate,_umalloc,_ucalloc,_uclose,_udestroy functions
// fortunately, the pointer variables SOMCalloc,SOMFree,SOMMalloc,SOMRealloc
// are kept in this DLL's data segment which makes it possible to replace
// the memory management functions for this DLL only
SOMEXTERN somTD_SOMCalloc * SOMDLINK SOMCalloc = MyCalloc;
SOMEXTERN somTD_SOMFree * SOMDLINK SOMFree = MyFree;
SOMEXTERN somTD_SOMMalloc * SOMDLINK SOMMalloc = MyMalloc;
SOMEXTERN somTD_SOMRealloc * SOMDLINK SOMRealloc = MyRealloc;
char buf[8192];
char devBuf[MAX_RM_NODE_SIZE];
char parentdevBuf[MAX_RM_NODE_SIZE];
char drvBuf[MAX_RM_NODE_SIZE];
HMODULE gModule=NULLHANDLE;
HDRIVER ReturnKernelDriverNode(void)
{
HDRIVER hDriver = NULLHANDLE;
PRM_GETNODE_DATA pDrvNode=(PRM_GETNODE_DATA)drvBuf;
APIRET rc;
ULONG i;
RM_ENUMNODES_PARM Cmd={RM_COMMAND_DRVR};
PRM_ENUMNODES_DATA pNodes=(PRM_ENUMNODES_DATA)buf;
memset(buf,0,sizeof(buf));
rc = RMEnumNodes(&Cmd,pNodes,sizeof(buf));
for (i=0;i<pNodes->NumEntries ;i++ ) {
hDriver = pNodes->NodeEntry[i].RMHandle;
rc = RMGetNodeInfo(hDriver,pDrvNode,sizeof(drvBuf));
if (0 == strcmp("OS2KRNL",pDrvNode->RMNode.pDriverNode->DrvrName)) {
break;
} /* endif */
} /* endfor */
return hDriver;
}
#if (defined(__IBMC__) || defined(__IBMCPP__))
#define MEMSIZE 1024UL*128UL // allocate in chunks of 128 kB
Heap_t gHeap = NULL;
void * _LNK_CONV AllocateMoreMemory(Heap_t, size_t *size, int *clean)
{
APIRET rc = NO_ERROR;
PVOID ptr=NULL;
rc = DosAllocMem(&ptr,MEMSIZE,PAG_COMMIT|PAG_READ|PAG_WRITE|OBJ_ANY);
if (NO_ERROR != rc) {
ptr = NULL;
rc = DosAllocMem(&ptr,MEMSIZE,PAG_COMMIT|PAG_READ|PAG_WRITE);
}
if ((NO_ERROR == rc) && ptr) {
*size = MEMSIZE;
*clean = _BLOCK_CLEAN;
} /* endif */
return ptr;
}
void _LNK_CONV ReleaseMemory(Heap_t, void *ptr, size_t size)
{
if (ptr) {
DosFreeMem(ptr);
} /* endif */
}
/*
IMPORTANT NOTE ON CALLING _CRT_init and _CRT_term in any case, no matter if you link to the CRT statically or dynamically
<quote>
#: 172179 S4/IBM VisualAge C++
31-Jan-96 02:11:56
Sb: #Destructors at exit(int)
Fm: ROGER PETT [IBM] 73251,1733
To: Dean Roddey 72170,1614 (X)
OS/2 is supposed to run DLL termination in the opposite order to the DLL
initialization. Since static object destructors and CRT termination are
done in the DLL termination ocde, it is a problem if this does not happen.
Unfortunately, there *are* conditions where the DLL termination can run
"out of order". It's a known OS/2 bug, and I understand that it is not
fixable without some rather major surgery (i.e. it's likely to introduce new
bugs!).
Personally, I'd rather have the devil I know, since you can program your
way around it. For example:
In VAC++, the CRT exposes both _CRT_init() and _CRT_term(), and you
should call both, regardless of whether you statically or dynamically bind to
the runtime. This is a change from C Set++. We count the number of times
the runtime is initialized, and only completely shut down the runtime when
the number of _CRT_term() calls match the number of _CRT_init() calls. This
insures the runtime stays "alive" until all its users have terminated. We get
away with this because the OS doesn't immediately unload the DLL after
running the DLL termination.
Roger..
</quote>
*/
// we need to allocate in high memory for all SOM object and memory allocation
// we have to do this already on DLL load
// that's why we replace the DLL InitTerm routine with our own
ULONG APIENTRY _DLL_InitTerm(ULONG hMod,ULONG flag)
{
APIRET rc = NO_ERROR;
if (flag == 0)
{
gModule = hMod;
if (_CRT_init())
{
return 0;
}
#ifdef __cplusplus
__ctordtorInit();
#endif
if (!gHeap) {
PVOID ptr = NULL;
// allocate a large chunk of memory in high memory (OBJ_ANY attribute)
rc = DosAllocMem(&ptr,MEMSIZE,PAG_COMMIT|PAG_READ|PAG_WRITE|OBJ_ANY);
if (NO_ERROR != rc) {
ptr = NULL;
rc = DosAllocMem(&ptr,MEMSIZE,PAG_COMMIT|PAG_READ|PAG_WRITE);
}
if ((NO_ERROR == rc) && ptr) {
// create a private heap with the memory just allocated
gHeap = _ucreate(ptr,MEMSIZE,_BLOCK_CLEAN,_HEAP_REGULAR,AllocateMoreMemory,ReleaseMemory);
return 1;
}
else {
return 0;
}
}
else {
return 1;
}
}
else if (flag == 1)
{
if (gHeap) {
// destroy the private heap
_uclose(gHeap);
_udestroy(gHeap,_FORCE);
// free the large chunk of memory
gHeap = NULL;
}
#ifdef __cplusplus
__ctordtorTerm();
#endif
_CRT_term();
return 1;
}
else
{
return 0;
}
}
#endif
#if defined(__WATCOMC__)
// for Watcom, we just need to set a global flag to have
// malloc,calloc allocate memory from the high memory area
unsigned APIENTRY LibMain(unsigned hMod,unsigned flag)
{
if (flag == 0)
{
gModule = hMod;
// enable high memory
_use_os2_high_mem(1);
return 1;
}
else if (flag == 1)
{
return 1;
}
else
{
return 0;
} /* endif */
}
#endif
somToken SOMLINK MyCalloc(size_t element_count,size_t element_size)
{
#if (defined(__IBMC__) || defined(__IBMCPP__))
return _ucalloc(gHeap,element_count,element_size);
#else
return calloc(element_count,element_size);
#endif
}
void SOMLINK MyFree(somToken memory)
{
free(memory);
}
somToken SOMLINK MyMalloc(size_t nbytes)
{
#if (defined(__IBMC__) || defined(__IBMCPP__))
return _umalloc(gHeap,nbytes);
#else
return malloc(nbytes);
#endif
}
somToken SOMLINK MyRealloc(somToken memory,size_t nbytes)
{
return realloc(memory,nbytes);
}
/*
some oddities:
1) KeyObject,ProductObject,VendorObject,RMDeviceObject,USBDeviceColleciton,RMDeviceCollection
classes CANNOT be registered by exporting their relevant entry points via the DEF file
and having them invoked by the class registration mechanism
that's why we have to register them via the SOMInitModule function
2) WPDevCPUEx class can be exported via the DEF file but on registration the system will freeze
If we register it from the SOMInitModule function, everything is fine
3) WPHwManagerEx class HAS to export its relevant entry points via the DEF file
with the normal WPS registration process registering the class. Otherwise class REPLACEMENT
would not be possible (remember, WPHwManagerEx not only subclasses WPHwManager but also REPLACES it)
*/
SOMEXTERN VOID SOMLINK SOMInitModule(long majorVersion,long minorVersion, string className)
{
SOM_IgnoreWarning(majorVersion);
SOM_IgnoreWarning(minorVersion);
SOM_IgnoreWarning(className);
WinWaitForShell(WWFS_DESKTOPOPENED);
KeyObjectNewClass(KeyObject_MajorVersion,KeyObject_MinorVersion);
ProductObjectNewClass(ProductObject_MajorVersion,ProductObject_MinorVersion);
VendorObjectNewClass(VendorObject_MajorVersion,VendorObject_MinorVersion);
RMDeviceObjectNewClass(RMDeviceObject_MajorVersion,RMDeviceObject_MinorVersion);
USBDeviceCollectionNewClass(USBDeviceCollection_MajorVersion,USBDeviceCollection_MinorVersion);
RMDeviceCollectionNewClass(RMDeviceCollection_MajorVersion,RMDeviceCollection_MinorVersion);
WPDevCPUExNewClass(WPDevCPUEx_MajorVersion,WPDevCPUEx_MinorVersion);
return;
}
void _LNK_CONV RefreshThread(void *p)
{
WPHwManagerEx *somSelf = (WPHwManagerEx *)p;
WPHwManagerExData *somThis = WPHwManagerExGetData(somSelf);
QMSG qmsg;
HAB hab = WinInitialize(0);
/*
if you want to use WPS/SOM methods from a secondary thread
you always need to create a message queue as several methods
require it, we save the handle in the instance data so that we can
use it from the main thread to post messages to it
*/
somThis->hmqRefreshThread = WinCreateMsgQueue(hab,0);
/*
when the system shuts down you do not want a WM_QUIT message
posted to the queue. Instead we will post a WM_QUIT message
ourselves when the last icon/details/tree view is closed
*/
WinCancelShutdown(somThis->hmqRefreshThread,TRUE);
/*
start the periodic refresh timer
*/
ULONG timerId = WinStartTimer(hab,NULLHANDLE,0UL,2000);
/*
we will keep refreshing the view with the given repetition
interval for as long as an icon/details/tree view is open,
once the last view of these types is closed, we will
receive a WM_QUIT message from the main thread which
will make "WinGetMsg" return false
*/
while (WinGetMsg(hab,&qmsg,NULLHANDLE,0,0)) {
if ((qmsg.msg == WM_TIMER) && (SHORT1FROMMP(qmsg.mp1) == timerId)) {
somSelf->wpPopulate(0UL,NULL,FALSE);
} /* endif */
} /* endwhile */
/*
cleanup: stop the timer, destroy the message queue, reset the instance data
*/
WinStopTimer(hab,NULLHANDLE,timerId);
WinDestroyMsgQueue(somThis->hmqRefreshThread);
somThis->hmqRefreshThread = NULLHANDLE;
WinTerminate(hab);
/*
at this point we would normally need to call wpUnlockObject on somSelf
to set back the lock count, but since we did not need to lock in
wpAddToObjUseList, we don't need to do it here either
*/
}
/*
SOM spec 2.1 says to always override this routine for performance reasons
even if you don't change anything
*/
SOM_Scope void SOMLINK somDefaultInit(WPHwManagerEx *somSelf,
som3InitCtrl* ctrl)
{
WPHwManagerExData *somThis; /* set in BeginInitializer */
somInitCtrl globalCtrl;
somBooleanVector myMask;
WPHwManagerExMethodDebug("WPHwManagerEx","somDefaultInit");
WPHwManagerEx_BeginInitializer_somDefaultInit;
WPHwManagerEx_Init_WPHwManager_somDefaultInit(somSelf, ctrl);
/*
* local WPHwManagerEx initialization code added by programmer
*/
}
/*
SOM spec 2.1 says to always override this routine for performance reasons
even if you don't change anything
*/
SOM_Scope void SOMLINK somDestruct(WPHwManagerEx *somSelf, octet doFree,
som3DestructCtrl* ctrl)
{
WPHwManagerExData *somThis; /* set in BeginDestructor */
somDestructCtrl globalCtrl;
somBooleanVector myMask;
WPHwManagerExMethodDebug("WPHwManagerEx","somDestruct");
WPHwManagerEx_BeginDestructor;
/*
* local WPHwManagerEx deinitialization code added by programmer
*/
WPHwManagerEx_EndDestructor;
}
/*
* wpDeleteFromObjUseList :override;
*/
SOM_Scope BOOL SOMLINK wpPopulate(WPHwManagerEx *somSelf, ULONG ulReserved,
PSZ pszPath, BOOL fFoldersOnly)
{
/* WPHwManagerExData *somThis = WPHwManagerExGetData(somSelf); */
M_WPHwManagerExData *somMThis = M_WPHwManagerExGetData(_WPHwManagerEx);
WPHwManagerExMethodDebug("WPHwManagerEx","wpPopulate");
BOOL fRc = FALSE;
WPDevice *obj=NULL,*nextObj=NULL,*newObj=NULL;
M_WPDevice *classObj=NULL;
APIRET rc;
RM_ENUMNODES_PARM Cmd={RM_COMMAND_PHYS};
PRM_ENUMNODES_DATA pData=(PRM_ENUMNODES_DATA)buf;
PRM_GETNODE_DATA pDevNode=(PRM_GETNODE_DATA)devBuf;
PRM_GETNODE_DATA pParentDevNode=(PRM_GETNODE_DATA)parentdevBuf;
PRM_GETNODE_DATA pDrvNode=(PRM_GETNODE_DATA)drvBuf;
PRESOURCELIST pResourceList;
PSZ pszTitle = NULL;
ULONG depth = 0UL;
ULONG i,j;
RMHANDLE parentHandles[10] = {0};
RMHANDLE uniqueHandle = 0;
RMHANDLE drvHandle = 0;
ULONG nodeType = 0;
USHORT baseType = 0;
USHORT subType = 0;
USHORT ifType = 0;
FDATE date;
char strBuffer[512];
BOOL fHide;
APIRET rcFindSemSuccess;
APIRET rcFolderSemSuccess;
VendorObject *pV;
ProductObject *pP;
RMDeviceObject *pR;
Environment *ev = somGetGlobalEnvironment();
RMDeviceCollection *pRMColl = new RMDeviceCollection;
/*
initial note: the resource manager (RM) defines driver, adapter and device plus a couple of other "classes" that are not
relevant here. The HW Manager uses a device class "WPDevice" plus some derived device classes like "WPDevCDRom", see
below. This is peculiar and makes it necessary to structurally force the RM driver, adapter and device "classes" attributes into the one "WPDevice" class
that HW manager uses. The net effect is that there will be a WPDevice object for a RM adapter with the relevant adapter parameters
"base class" and "subclass". On the other hand there will be a WPDevice object for a RM device but that object will only have room
for RM adapter parameters and not the RM device parameters. The compromise is to use the parent RM adapter's base class and subclass
parameters for a RM device in the corresponding WPDevice object ...
*/
/* better add exception handling for whenever you request any of the semaphores */
/* if you trap before releasing the semaphore, the system will enter a catastrophic state ... */
/* gleaned from XWorkplace implementation */
TRY(exc)
/*
undocumented: you need to request the find mutex before you start populating a folder
gleaned this from the XWorkplace implementation
*/
if ((rcFindSemSuccess = somMThis->wpRequestFindMutexSem(somSelf,1000)) == NO_ERROR) {
/*
first thing is to get the complete RM node list of all RM adapters and RM devices
that's what you get when you specify Cmd = RM_COMMAND_PHYS
*/
memset(pData,0,sizeof(buf));
rc = RMEnumNodes(&Cmd,pData,sizeof(buf));
/* better add exception handling for whenever you request any of the semaphores */
/* if you trap before releasing the semaphore, the system will enter a catastrophic state ... */
/* gleaned from XWorkplace implementation, see except.h for the macro implementation */
TRY(exc2)
/*
undocumented: you need to request the folder mutex sem before you start to manipulate
(add, delete) the content list, gleaned this from the XWorkplace implementation
*/
if ((rcFolderSemSuccess = somMThis->wpRequestFolderMutexSem(somSelf,1000)) == NO_ERROR) {
somSelf->wpModifyFldrFlags( FOI_POPULATEDWITHALL|FOI_POPULATEDWITHFOLDERS|FOI_POPULATEINPROGRESS,
FOI_POPULATEINPROGRESS);
/* first for every existing object we check if it (still) exists in the RM tree */
/* if not, we are going to remove it */
/* add. note: objects derived from WPTransient (like WPDevice) are always awake */
/* there is no need to awaken them, they will also never go dormant */
obj = (WPDevice *)somSelf->wpQueryContent(NULL,QC_FIRST);
while (obj) {
nextObj = (WPDevice *)somSelf->wpQueryContent(obj,QC_NEXT);
uniqueHandle = somMThis->wpGetUniqueID(obj);
for (i=0;i<pData->NumEntries;i++) {
if (pData->NodeEntry[i].RMHandle == uniqueHandle) {
/* "misuse" the upper bit of the depth field in order to track if this RM node has a matching object */
pData->NodeEntry[i].Depth |= 0x80000000UL;
break;
} /* endif */
} /* endfor */
if (i >= pData->NumEntries) {
/* no corresponding RM node could be found for this object, delete the object */
obj->wpFree();
/* also delete the corresponding object from the RM node collection */
pRMColl->deleteRMDevice(ev,uniqueHandle);
} /* endif */
else {
obj->wpUnlockObject();
}
obj = nextObj;
} /* endwhile */
/* now we go through the RM nodes list again */
/* for every RM node where we did not yet find a corresponding object */
/* create a new WPDevice (or derived thereof) object */
/* unfortunately, the class tree of WPDevice and derived classes is brain dead in */
/* that we have to create objects of different class for different types of devices only because of differing icons */
/* where it would have been much simpler to just adjust the icon of the object depending on device type ... */
for (i=0;i<pData->NumEntries;i++) {
depth = pData->NodeEntry[i].Depth & ~0x80000000UL;
parentHandles[depth] = pData->NodeEntry[i].RMHandle;
if (!(pData->NodeEntry[i].Depth & 0x80000000UL)) {
pData->NodeEntry[i].Depth |= 0x80000000UL;
uniqueHandle = pData->NodeEntry[i].RMHandle;
rc = RMGetNodeInfo(uniqueHandle,pDevNode,sizeof(devBuf));
nodeType = pDevNode->RMNode.NodeType;
fHide = FALSE;
switch(nodeType) {
case RMTYPE_ADAPTER:
pszTitle = pDevNode->RMNode.pAdapterNode->AdaptDescriptName;
baseType = pDevNode->RMNode.pAdapterNode->BaseType;
subType = pDevNode->RMNode.pAdapterNode->SubType;
ifType = pDevNode->RMNode.pAdapterNode->InterfaceType;
drvHandle = pDevNode->RMNode.DriverHandle;
classObj = NULL;
break;
case RMTYPE_DEVICE:
pszTitle = pDevNode->RMNode.pDeviceNode->DevDescriptName;
/* for a RM device node, "depth" will always be > 0 and the parent node will be an RM adapter node */
rc = RMGetNodeInfo(parentHandles[depth-1],pParentDevNode,sizeof(parentdevBuf));
/* for the next three lines, see initial note */
baseType = pParentDevNode->RMNode.pAdapterNode->BaseType;
subType = pParentDevNode->RMNode.pAdapterNode->SubType;
ifType = pParentDevNode->RMNode.pAdapterNode->InterfaceType;
drvHandle = pDevNode->RMNode.DriverHandle;
if (pDevNode->RMNode.pDeviceNode->DevType == DS_TYPE_CDROM) {
classObj = (M_WPDevice *)_WPDevCDRom;
} /* endif */
else if (pDevNode->RMNode.pDeviceNode->DevType == DS_TYPE_WORM) {
classObj = (M_WPDevice *)_WPDevCDRom;
} /* endif */
else if (pDevNode->RMNode.pDeviceNode->DevType == DS_TYPE_OPT_MEM) {
classObj = (M_WPDevice *)_WPDevCDRom;
} /* endif */
else if (pDevNode->RMNode.pDeviceNode->DevType == DS_TYPE_DISK) {
classObj = (M_WPDevice *)_WPDevHarddrive;
} /* endif */
else if (pDevNode->RMNode.pDeviceNode->DevType == DS_TYPE_TAPE) {
classObj = (M_WPDevice *)_WPDevTape;
} /* endif */
else if (pDevNode->RMNode.pDeviceNode->DevType == DS_TYPE_SLOT) {
classObj = (M_WPDevice *)_WPDevBus;
} /* endif */
else if (pDevNode->RMNode.pDeviceNode->DevType == DS_TYPE_UNKNOWN) {
classObj = (M_WPDevice *)_WPDevice;
} /* endif */
else {
classObj = NULL;
}
if (pDevNode->RMNode.pDeviceNode->DevType == DS_TYPE_PLANAR_CHIPSET) {
fHide = TRUE;
} /* endif */
break;
default:
pszTitle = NULL;
baseType = AS_BASE_RESERVED;
subType = AS_SUB_OTHER;
ifType = AS_INTF_GENERIC;
drvHandle = pDevNode->RMNode.DriverHandle;
classObj = NULL;
break;
}
if (!classObj) {
if (uniqueHandle == HANDLE_PHYS_TREE ) {
classObj = _WPDevice;
} /* endif */
else if (uniqueHandle == HANDLE_DEFAULT_SYSBUS ) {
classObj = (M_WPDevice *)_WPDevBus;
} /* endif */
else if (uniqueHandle == HANDLE_X_BUS) {
classObj = (M_WPDevice *)_WPDevBus;
} /* endif */
else if (uniqueHandle == HANDLE_PCI_BUS) {
classObj = (M_WPDevice *)_WPDevBus;
} /* endif */
else if (baseType == AS_BASE_BRIDGE) {
classObj = (M_WPDevice *)_WPDevBus;
} /* endif */
else if (baseType == AS_BASE_DISPLAY) {
classObj = (M_WPDevice *)_WPDevDisplay;
}
else if ((baseType == AS_BASE_INPUT) && (subType == AS_SUB_KBD)) {
classObj = (M_WPDevice *)_WPDevKeyboard;
}
else if ((baseType == AS_BASE_INPUT) && (subType == AS_SUB_MOUSE)) {
classObj = (M_WPDevice *)_WPDevMouse;
}
else if ((baseType == AS_BASE_COMM) && (subType == AS_SUB_PARALLEL)) {
classObj = (M_WPDevice *)_WPDevParallel;
}
else if ((baseType == AS_BASE_COMM) && (subType == AS_SUB_SERIAL)) {
classObj = (M_WPDevice *)_WPDevSerial;
}
else if ((baseType == AS_BASE_PERIPH) && (subType == AS_SUB_TIMER)) {
classObj = (M_WPDevice *)_WPDevTimer;
}
else if ((baseType == AS_BASE_PERIPH) && (subType == AS_SUB_RTC)) {
classObj = (M_WPDevice *)_WPDevTimer;
}
else if (baseType == AS_BASE_PERIPH) {
classObj = (M_WPDevice *)_WPDevPeriph;
}
else if (baseType == AS_BASE_MEMORY) {
classObj = (M_WPDevice *)_WPDevMemory;
}
else if (baseType == AS_BASE_BIOS_ROM) {
classObj = (M_WPDevice *)_WPDevMemory;
}
else if ((baseType == AS_BASE_MSD) && (subType == AS_SUB_FLPY)) {
classObj = (M_WPDevice *)_WPDevDiskette;
}
else if (baseType == AS_BASE_MSD) {
classObj = (M_WPDevice *)_WPDevHarddrive;
}
else if ((baseType == AS_BASE_MMEDIA) && (subType == AS_SUB_MM_AUDIO)) {
classObj = (M_WPDevice *)_WPDevAudio;
}
else if ((baseType == 0) && (subType == 0) && (ifType == 0)) {
classObj = (M_WPDevice *)_WPDevCPUEx;
}
else {
classObj = _WPDevice;
}
} /* endif */
/*
query the associated driver info here
we need it later on to fill the relevant fields for the WPDevice
settings notebook
*/
rc = RMGetNodeInfo(drvHandle,pDrvNode,sizeof(drvBuf));
/*
this deals with a very special problem:
in order to place it correctly into the hierarchy of a tree view,
each device object has a unique ID (identical to the RM handle)
and a parent ID (identical to the RM handle of its parent in the RM tree)
you could set these values with the "wpSetUnique" and "wpSetParentID" methods
however, these values are needed by "wpCnrInsertObject" in order to correctly
set the parent of the PMINIRECORDCORE record (for tree views)
if any view of HW Manager is already open during object creation,
"wpCnrInsertObject" is called already during "wpclsNew" processing,
therefore, calling "wpSetUnique" and "wpSetParentID" AFTER calling "wpclsNew" would be too late
that's why it was obviously decided to make these values Setup strings
so that these values are already available on object creation
strictly speaking, UNIQUEID could have also been set after object creation
but PARENTID is mandatory to be set already on object creation
note: I found these setup strings in PNP.DLL by expanding the DLL (lxlite /X) and looking at it
with a text editor ...
there are RM device objects below PIC_0,PIC_1,DMA_CTRL_0,DMA_CTRL_1,TIMER
which should not show up in the HW manager tree
instead of skipping these, we just make them invisible which is easier to manage
as then the objects exist and can be checked for but they won't be visible in any view
*/
sprintf(strBuffer,"UNIQUEID=%u;PARENTID=%u;NOTVISIBLE=%s;NORENAME=YES;",uniqueHandle,depth ? parentHandles[depth-1]: 0,fHide ? "YES" : "NO");
/* wpclsNew will also add to the folder content list (wpAddToContent is called) */
/* wpclsNew will also call wpCnrInsertObject on the new object for every view currently open */
newObj= (WPDevice *)classObj->wpclsNew(pszTitle,strBuffer,somSelf,TRUE);
/*
reset the title for all objects that represent a USB device
to the vendor/product string that we queried from file "usb.ids"
*/
pR = NULL; pV = NULL; pP = NULL;
// search the device in the device data base:
// "uniqueHandle" is the RM device node
// which is the lookup key to find the vendor and device string
pR = pRMColl->findRMDevice(ev,uniqueHandle);
if (pR && somMThis->pUSBColl) {
pV = somMThis->pUSBColl->findVendor(ev,pR->_get_idVendor(ev));
}
if (pV) {
pP = pV->findProduct(ev,pR->_get_idProduct(ev));
} /* endif */
if (pV && pP) {
sprintf(strBuffer,"%s\n%s",pV->_get_vendorName(ev),pP->_get_productName(ev));
newObj->wpSetTitle(strBuffer);
} /* endif */
/*
reset the title for objects of class "WPDevCPU"
to display the brand string of the CPU
*/
if (classObj == (M_WPDevice *)_WPDevCPUEx) {
cpuGetBrandString(strBuffer,sizeof(strBuffer));
newObj->wpSetTitle(strBuffer);
} /* endif */
somMThis->wpSetNodeType(newObj,nodeType);
somMThis->wpSetNodeBaseType(newObj,baseType);
somMThis->wpSetNodeSubType(newObj,subType);
somMThis->wpSetDeviceDriver(newObj,pDrvNode->RMNode.pDriverNode->DrvrName);
somMThis->wpSetDDName(newObj,pDrvNode->RMNode.pDriverNode->DrvrDescript);
somMThis->wpSetDDVendor(newObj,pDrvNode->RMNode.pDriverNode->VendorName);
sprintf(strBuffer,"%u.%u",pDrvNode->RMNode.pDriverNode->MajorVer,pDrvNode->RMNode.pDriverNode->MinorVer);
somMThis->wpSetDDVersion(newObj,strBuffer);
date.year = pDrvNode->RMNode.pDriverNode->Date.Year - 1980;
date.month = pDrvNode->RMNode.pDriverNode->Date.Month;
date.day = pDrvNode->RMNode.pDriverNode->Date.Day;
somMThis->wpSetDDDate(newObj,&date);
/*
finally, we go through the RM resource list for this RM node and add all found resources
to the corresponding device object
*/
pResourceList = pDevNode->RMNode.pResourceList;
if (pResourceList) {
for (j=0;j<pResourceList->Count;j++ ) {
switch (pResourceList->Resource[j].ResourceType) {
case RS_TYPE_IO:
somMThis->wpAddIOResource(newObj,&pResourceList->Resource[j].IOResource);
break;
case RS_TYPE_IRQ:
somMThis->wpAddIRQResource(newObj,&pResourceList->Resource[j].IRQResource);
break;
case RS_TYPE_MEM:
somMThis->wpAddMemoryResource(newObj,&pResourceList->Resource[j].MEMResource);
break;
case RS_TYPE_DMA:
somMThis->wpAddDMAResource(newObj,&pResourceList->Resource[j].DMAResource);
break;
} /* endswitch */
} /* endfor */
/*
the resource info will be shown in the details view, that's why we have to invoke the following
method call in order to properly update any details view
*/
newObj->wpCnrRefreshDetails();
}
newObj->wpUnlockObject();
} /* endif */
} /* endfor */
/*
the wpPopulate implementation of WPFolder does a whole bunch of undocumented
things so that view update on folder population will actually work
WPHwManager inherits from WPFolder but we cannot call WPHwManager's wpPopulate
method because we want to replace part of its implementation with our own
that's why we cast our object to WPFolder in order to call the WPFolder implemenation
of wpPopulate
after we have called WPFolders implementation of wpPopulate we cast back to our own
class so that we can continue processing as if nothing has happened
*/
somSelf->somCastObj(_WPFolder);
fRc = somSelf->wpPopulate(ulReserved,pszPath,fFoldersOnly);
somSelf->somResetObj();
somSelf->wpModifyFldrFlags(FOI_POPULATEDWITHALL|FOI_POPULATEDWITHFOLDERS|FOI_POPULATEINPROGRESS,FOI_POPULATEDWITHALL|FOI_POPULATEDWITHFOLDERS);
}
ENDTRY(exc2);
if (rcFolderSemSuccess == NO_ERROR) {
somMThis->wpReleaseFolderMutexSem(somSelf);
} /* endif */
}
ENDTRY(exc);
if (rcFindSemSuccess == NO_ERROR) {
somMThis->wpReleaseFindMutexSem(somSelf);
} /* endif */
if (pRMColl) {
delete pRMColl;
pRMColl = NULL;
} /* endif */
return fRc;
}
/*
* The prototype for wpInitData was replaced by the following prototype:
*/
SOM_Scope void SOMLINK wpInitData(WPHwManagerEx *somSelf)
{
WPHwManagerExData *somThis = WPHwManagerExGetData(somSelf);
WPHwManagerExMethodDebug("WPHwManagerEx","wpInitData");
WPHwManagerEx_parent_WPHwManager_wpInitData(somSelf);
somThis->hmqRefreshThread = NULLHANDLE;
}
SOM_Scope BOOL SOMLINK wpAddToObjUseList(WPHwManagerEx *somSelf,
PUSEITEM pUseItem)
{
WPHwManagerExData *somThis = WPHwManagerExGetData(somSelf);
WPHwManagerExMethodDebug("WPHwManagerEx","wpAddToObjUseList");
if (pUseItem->type == USAGE_OPENVIEW) {
ULONG openViews = 0;
PVIEWITEM pViewItem = somSelf->wpFindViewItem(VIEW_ANY,NULL);
while (pViewItem) {
openViews++;
pViewItem = somSelf->wpFindViewItem(VIEW_ANY,pViewItem);
};
if (openViews == 0) {
/*
at this point we would normally need to call wpLockObject on somSelf
to ensure that it does not go dormant when it is used asychronously
from the secondary thread. However, when a view opens, the object
is locked once anyways, therefore there is no need to do it
*/
_beginthread(RefreshThread,NULL,0x8000,somSelf);
}
} /* endif */
return (WPHwManagerEx_parent_WPHwManager_wpAddToObjUseList(somSelf,
pUseItem));
}
SOM_Scope BOOL SOMLINK wpDeleteFromObjUseList(WPHwManagerEx *somSelf,
PUSEITEM pUseItem)
{
WPHwManagerExData *somThis = WPHwManagerExGetData(somSelf);
WPHwManagerExMethodDebug("WPHwManagerEx","wpDeleteFromObjUseList");
if (pUseItem->type == USAGE_OPENVIEW) {
ULONG openViews = 0;
PVIEWITEM pViewItem = somSelf->wpFindViewItem(VIEW_ANY,NULL);
while (pViewItem) {
openViews++;
pViewItem = somSelf->wpFindViewItem(VIEW_ANY,pViewItem);
};
if (openViews == 1 && somThis->hmqRefreshThread) {
WinPostQueueMsg(somThis->hmqRefreshThread,WM_QUIT,MPVOID,MPVOID);
}
} /* endif */
return (WPHwManagerEx_parent_WPHwManager_wpDeleteFromObjUseList(somSelf,
pUseItem));
}
SOM_Scope void SOMLINK wpclsInitData(M_WPHwManagerEx *somSelf)
{
/*
look at the SOM specification for SOM 2.1 how you can easily create static
somIDs from static text strings
another (more resource consuming) alternative would be to call somIdFromString()
but we take the easy way out
*/
static char *mthd1 = "wpSetUniqueID";
static char *mthd2 = "wpSetParentID";
static char *mthd3 = "wpSetNodeType";
static char *mthd4 = "wpSetNodeBaseType";
static char *mthd5 = "wpSetNodeSubType";
static char *mthd6 = "wpSetDDDate";
static char *mthd7 = "wpSetDeviceDriver";
static char *mthd8 = "wpSetDDName";
static char *mthd9 = "wpSetDDVendor";
static char *mthd10 = "wpSetDDVersion";
static char *mthd11 = "wpAddIRQResource";
static char *mthd12 = "wpAddDMAResource";
static char *mthd13 = "wpAddIOResource";
static char *mthd14 = "wpAddMemoryResource";
static char *mthd15 = "wpGetUniqueID";
static char *mthd16 = "wpRequestFolderMutexSem";
static char *mthd17 = "wpReleaseFolderMutexSem";
static char *mthd18 = "wpRequestFindMutexSem";
static char *mthd19 = "wpReleaseFindMutexSem";
static somId theId1 = &mthd1;
static somId theId2 = &mthd2;
static somId theId3 = &mthd3;
static somId theId4 = &mthd4;
static somId theId5 = &mthd5;
static somId theId6 = &mthd6;
static somId theId7 = &mthd7;
static somId theId8 = &mthd8;
static somId theId9 = &mthd9;
static somId theId10 = &mthd10;
static somId theId11 = &mthd11;
static somId theId12 = &mthd12;
static somId theId13 = &mthd13;
static somId theId14 = &mthd14;
static somId theId15 = &mthd15;
static somId theId16 = &mthd16;
static somId theId17 = &mthd17;
static somId theId18 = &mthd18;
static somId theId19 = &mthd19;
M_WPHwManagerExData *somThis = M_WPHwManagerExGetData(somSelf);
M_WPHwManagerExMethodDebug("M_WPHwManagerEx","wpclsInitData");
M_WPHwManagerEx_parent_M_WPHwManager_wpclsInitData(somSelf);
/* we have to load WPDevice class because we are making use of the Metaclass object _WPDevice */
WPDeviceNewClass(WPDevice_MajorVersion,WPDevice_MinorVersion);
/* lock the WPDevice class object once so that the WPDevice class DLL (PNP.DLL) will not get unloaded prematurely */
_WPDevice->wpclsIncUsage();
/*
what we do here is resolve a couple of WPDevice methods by name because they are not publicly
exported via IDL (but we need them, see wpPopulate).
Because we do this here, we don't have to do it again and again whenever we need them.
We also save away the function pointers in the WPHwManagerEx class OBJECT
and NOT in the individual WPHwManagerEx class INSTANCE(S) as the class object is the central
place to store things that are useful to ALL instances of the WPHwManagerEx class
note: all these method names were found by using XWorkplace's WPS class list browser.
The method signatures (parameters, return value) were found by using Theseus memory view
(and it's disassembling capabilities) and some good portion of guesswork
*/
somThis->wpSetUniqueID = (PFN_SETUNIQUEID)_WPDevice->somFindSMethod(theId1);
somThis->wpSetParentID = (PFN_SETPARENTID)_WPDevice->somFindSMethod(theId2);
somThis->wpSetNodeType = (PFN_SETNODETYPE)_WPDevice->somFindSMethod(theId3);
somThis->wpSetNodeBaseType = (PFN_SETNODEBASETYPE)_WPDevice->somFindSMethod(theId4);
somThis->wpSetNodeSubType = (PFN_SETNODESUBTYPE)_WPDevice->somFindSMethod(theId5);
somThis->wpSetDDDate = (PFN_SETDDDATE)_WPDevice->somFindSMethod(theId6);
somThis->wpSetDeviceDriver = (PFN_SETDEVICEDRIVER)_WPDevice->somFindSMethod(theId7);
somThis->wpSetDDName = (PFN_SETDDNAME)_WPDevice->somFindSMethod(theId8);
somThis->wpSetDDVendor = (PFN_SETDDVENDOR)_WPDevice->somFindSMethod(theId9);
somThis->wpSetDDVersion = (PFN_SETDDVERSION)_WPDevice->somFindSMethod(theId10);
somThis->wpAddIRQResource = (PFN_ADDIRQRESOURCE)_WPDevice->somFindSMethod(theId11);
somThis->wpAddDMAResource = (PFN_ADDDMARESOURCE)_WPDevice->somFindSMethod(theId12);
somThis->wpAddIOResource = (PFN_ADDIORESOURCE)_WPDevice->somFindSMethod(theId13);
somThis->wpAddMemoryResource = (PFN_ADDMEMORYRESOURCE)_WPDevice->somFindSMethod(theId14);
somThis->wpGetUniqueID = (PFN_GETUNIQUEID)_WPDevice->somFindSMethod(theId15);
somThis->wpRequestFolderMutexSem = (PFN_WPREQUESTFOLDERMUTEXSEM)_WPHwManagerEx->somFindSMethod(theId16);
somThis->wpReleaseFolderMutexSem = (PFN_WPRELEASEFOLDERMUTEXSEM)_WPHwManagerEx->somFindSMethod(theId17);
somThis->wpRequestFindMutexSem = (PFN_WPREQUESTFINDMUTEXSEM)_WPHwManagerEx->somFindSMethod(theId18);
somThis->wpReleaseFindMutexSem = (PFN_WPRELEASEFINDMUTEXSEM )_WPHwManagerEx->somFindSMethod(theId19);
somThis->pUSBColl = new USBDeviceCollection;
{
ULONG ulNum,ulBootTime,i;
HDRIVER hDriver=NULLHANDLE;
HADAPTER hAdapter=NULLHANDLE;
APIRET rc;
ADJUNCT adaptNum={0};
ADJUNCT adaptModel={0};
ADAPTERSTRUCT adptStruct = {"CPU_# ???",0,0,0,0,AS_HOSTBUS_PLANAR,AS_BUSWIDTH_32BIT,&adaptNum};
// we need to add CPU nodes to the RM tree, unfortunately we cannot distinguish
// between a WPS restart and a reboot but we need to prevent adding additional
// nodes on WPS restart
// the only way out is to check the time since boot, if it is smaller than
// 90 sec (1.5 minutes) we assume it is a reboot and not a WPS restart
rc = DosQuerySysInfo(QSV_MS_COUNT,QSV_MS_COUNT,&ulBootTime,sizeof(ulBootTime));
rc += DosQuerySysInfo(QSV_NUMPROCESSORS,QSV_NUMPROCESSORS,&ulNum,sizeof(ulNum));
if ((NO_ERROR == rc) && (ulBootTime < 90000UL) ) {
// work around a compile issue
// we need to redefine this macro to return a ULONG value
// otherwise the 32-bit compiler will reject it
// and complain on using ADJ_HEADER_SIZE
#undef FIELDOFFSET
#define FIELDOFFSET(type, field) ((ULONG)&(((type *)0)->field))
// there is a bug in RMCreateAdapter in that you HAVE TO
// specify at least one adjunct element,
// otherwise "RMCreateAdapter" will trap !
// we specify those adjunct structures that are also specified
// for the already existing node "CPU_0 ???"
adaptNum.pNextAdj = &adaptModel;
adaptNum.AdjLength = ADJ_HEADER_SIZE + sizeof(USHORT);
adaptNum.AdjType = ADJ_ADAPTER_NUMBER;
adaptModel.pNextAdj = NULL;
adaptModel.AdjLength = ADJ_HEADER_SIZE + sizeof(USHORT);
adaptModel.AdjType = ADJ_MODEL_INFO;
adaptModel.Model_Info = 0xFC01;
hDriver = ReturnKernelDriverNode();
for (i=1;i<ulNum;i++) {
adaptNum.Adapter_Number = i;
hAdapter = NULLHANDLE;
RMCreateAdapter(hDriver,&hAdapter,&adptStruct,NULLHANDLE,NULL);
} /* endfor */
} /* endif */
}
}
SOM_Scope void SOMLINK wpclsUnInitData(M_WPHwManagerEx *somSelf)
{
M_WPHwManagerExData *somThis = M_WPHwManagerExGetData(somSelf);
M_WPHwManagerExMethodDebug("M_WPHwManagerEx","wpclsUnInitData");