;       SCCSID = @(#)smrgetid.asm       6.2 92/01/28
;       SCCSID @(#)smrgetid.asm 6.2 92/01/28
PAGE 60,132    ;
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;***************************************************************************
;
; Source File Name:     SMGGSGID.ASM
;
; Subroutine Name:      DOSSMGETSGID
;
; Descriptive Name:     Get the next available screen group number.
;
; Function:     Searches the array of words used to track free screen
;               group numbers and returns the first available screen
;               group number.
;
; Notes:
;       Dependencies:   The queue must be protected by a RAM
;                       semaphore from the calling subroutine.
;
;       Restrictions:   None
;
; Change History:
;   @MHW 09/13/90  PTR B715818 In-line performance (MMIO) hooks
;   CJ50 01/26/92  PTR B731426 Fix to allow 256 sessions.
;   MDLL 01/10/94  BJN Page Tune segments for Merged DLL.
;
; Entry Point:
;       Linkage:  EXTRN DOSSMGETSGID:NEAR
;                       CALL    DOSSMGETSGID
;
; Inputs:
;       DS      RDATA       Active screen group queue selector
;       DX      ProgramType Value = 1, Full Screen screen group
;                           Value = 2, Windowed VIO screen group
;                           Value = 3, PM screen group
;                           Value = 4, VDM screen group
;                           Value = 7, Windowed VDM screen group
;
; Exit Normal:
;       AX      ReturnCode Value = 0, screen group number found
;       DX      SGID       Screen group number
;                          DH = Screen Group Type
;                          DL = Screen Group Number
;
; Exit Errors:
;       AX      ReturnCode error_smg_no_sessions
;       DX      Destroyed
;
; Effects:      All other registers preserved.
;
; Internal References:
;                       The following data is in a shared data segment(SDATA)
;
;                       queueselector - active screen group queue selector
;
;          Routines:
;
; External References:
;          Routines:
;
;***************************************************************************
ifdef I1
;
;  Scan FreeGroups DWORDs for a free bit (set to 0)
;  If one is found
;    Mark it as in use
;    Calculate SG number
;    Increment number of used Screen Groups
;  Else
;    RC = Error_SMG_No_Sessions
;  EndIf
;
;***************************************************************************
else

.386C

   EXTRN FreeGroups           : DWORD
   EXTRN Last_Dword           : WORD
   EXTRN MaxFullScrnGrps      : WORD
   EXTRN UsedScrnGrps         : WORD
.xlist
   INCLUDE SMRSGCB.INC
   INCLUDE INFOSEG.INC                  ; needed by smmmpha.inc         ;MHW
   INCLUDE SMMMPHA.INC                  ; Performance hook macros       ;MHW
.xcref
   INCLUDE ERROR2.INC
   INCLUDE STRUC.INC
   INCLUDE SMRRDATA.INC
.cref
.list

CODE_TUNE1 SEGMENT WORD PUBLIC 'CODE' USE16                             ;MDLL
   ASSUME CS:CODE_TUNE1,DS:RDATA,SS:NOTHING,ES:NOTHING                  ;MDLL

PUBLIC       DOSSMGETSGID
DOSSMGETSGID PROC NEAR

;**********************************************************************
;*          Layout of Free Screen Groups Bit Map - Free_SGs           *
;*                                                                    *
;* There are 8 DWORDs for a total of 256 entries.  Each DWORD holds   *
;* 32 bits, representing 32 Screen Groups.  The first DWORD           *
;* represents Screen Groups 0-31, the second represents 32-63, etc.   *
;* The Right Most Bit (LSB) in a DWORD corresponds to the lowest      *
;* numbered Screen Group in that DWORD.                               *
;*                                                                    *
;* If the bit is 1, the Screen Group is in use, and if the bit is 0,  *
;* the Screen Group is free.                                          *
;*                                                                    *
;* Here is a diagram of the layout of the Free Screen Group Bit Map   *
;* ÚÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÂÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄ¿  *
;* ³31..0³63..32³95..64³127..96³159..128³191..160³223..192³255..224³  *
;* ÀÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÁÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÙ  *
;**********************************************************************

;  ENTER 0,0                                                            ;CJ10
   PUSH ECX                            ; Save registers
   PUSH SI
   PUSH BX

  MMPHPreDOSSMGetSGId                   ; Performance Hook (8103h)      ;MHW

   MOV  SI, OFFSET FreeGroups          ; Index
   XOR  BX, BX                         ; Use as a counter
   CLD                                 ; Go forward
   .Repeat
     INC  BX                           ; Loop counter
     LODSD                             ; Get 32 Free_SGs bits

ifdef USERANGES
     .IF < DX ae 3 >                    ; If a PM or VDM
       INC  BX                          ; Loop counter
       LODSD                            ; Get 2nd DWORD (ie start at SG 32)
       .IF < DX a 3 >                   ; If VDM
         MOV  AX, 0FFFFh                ; Fill up SGs 32-47
       .ENDIF
     .ENDIF
endif
;    **************************************************************
;    *  EAX contains 32 bits.  Bits 0..15 are for Full Screen     *
;    *  Sessions only, so we must skip over them if this is for   *
;    *  any other type of session.  If it is a FS session, don't  *
;    *  bother checking the first 4 bits since the first 4 SGs    *
;    *  are reserved, and set SI so we will exit the .REPEAT      *
;    *  statement after the first pass.                           *
;    **************************************************************
     MOV  ECX, 1                       ; This also clears upper WORD of ECX for BTS
     .If < EAX ne 0FFFFFFFFh >         ; Don't check if all set to 1.
       .If < DX eq FS_Type >           ; Full screen session; Use SG 0-15 only
         MOV  CX, MaxFullScrnGrps      ; Max FS sessions
       .ElseIf < BX eq 1 >             ; Skip first 16 bits of first DWORD
         MOV  CX,  MaxFullScrnGrps     ; Only 16 non-FS sessions in 1st DWORD
         SHR  EAX, CL                  ; Since they're for Full Screen only
       .Else                           ; Not FS, and Not 1st DWORD
         MOV  CX, 32                   ; At least 1 not set, so check all 32.
       .EndIf                          ; End Test for First DWORD
     .EndIf

     .Repeat                           ; Look for a bit reset to 0
       SHR  EAX, 1                     ; Check a bit
     .Leave nc                         ; Found a 0 (free SG)
     .Loop                             ; Check the next bit

   .Until < nc > OR                    ; Stop when we find a free SG OR
   .Until < SI a Last_Dword > OR       ; looked at all DWORDs           ;CJ50
   .Until < DX eq FS_Type >            ; Only 1 loop if it's a FS session

   .If < ncxz >                        ; Found Free SG? Set bit to used.
;    ******************************************************************
;    *  Now convert to a SG number.  SG# = ((SI-1) * 32) + (32 - CX)  *
;    ******************************************************************
     .If < DX eq FS_Type >             ; FS session; Use SG 0-...MaxFullScrnGrps
       MOV  AX, MaxFullScrnGrps        ; CX started at 16 instead of 32
     .Else                             ; Not FS
       MOV  AX, 32                     ; CX started at 32
     .EndIf

     SHL  DX, 8                        ; Put Session Type in upper byte
     PUSH SI                           ; Save pointer to correct DWORD
     SUB  SI, OFFSET FreeGroups        ; SI now index into Free_SGs
     SHR  SI, 2                        ; Divide by 4 since it inc'ed by 4
     DEC  SI                           ; (SI-1)
     SHL  SI, 5                        ; (SI-1) * 32
     SUB  AX, CX                       ; AX = 16/32 - CX
     MOV  CX, AX                       ; Save for BTS
     ADD  AX, SI                       ; AX = ((SI-1) * 16) + (16/32 - CX)
     MOV  DL, AL                       ; DL = SG#; DH = SG Type

;    ******************************************************
;    *  Set bit to indicate this Screen Group is in use.  *
;    ******************************************************
     POP  SI                           ; Restore pointer to correct DWORD
     SUB  SI, TYPE FreeGroups          ; Backup 1 DWORD because of LODSD
     BTS  DWORD PTR [SI], ECX          ; Set the bit in the DWORD

;    ******************************************************
;    *  Increment # of active Screen Groups and clear RC  *
;    ******************************************************
     INC  UsedScrnGrps
     XOR  EAX, EAX                     ; Set good return code
   .Else                               ; Didn't find a free SG
     XOR  EAX, EAX                     ; Clear upper WORD of EAX
     MOV  AX, Error_SMG_No_Sessions    ; Dummy return code
   .EndIf

   POP  BX                             ; Restore registers
   POP  SI
   POP  ECX

   MMPHPostDOSSMGetSGId                 ; Performance Hook (8183h)      ;MHW

;  LEAVE                                                                ;CJ10
   RET                                  ; Return to caller

DOSSMGETSGID ENDP
CODE_TUNE1 ENDS                                                         ;MDLL
endif
   END
