Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1102 lines
36 KiB

  1. page 80,132
  2. ;***************************************************************************;
  3. ;
  4. ; STACK.ASM
  5. ;
  6. ; Copyright (c) Microsoft Corporation 1989, 1990. All rights reserved.
  7. ;
  8. ; This module contains a routine that calls a callback function on a
  9. ; internal stack. This is designed to be used by MMSYSTEM drivers that
  10. ; call user callback functions at async interupt time.
  11. ;
  12. ; Revision history:
  13. ;
  14. ; 07/30/90 First created by ToddLa (moved from SndBlst driver)
  15. ; 04/24/91 MikeRo. Added stack usage stuff.
  16. ; 07/07/91 CurtisP. New stack switcher code that allows user to
  17. ; configure size and number of stacks. Default is 3
  18. ; frames of 1.5kb each. This is the minimum that MCISEQ
  19. ; needs in standard mode (running concurrent with wave).
  20. ; [mmsystem]!stackframes= and !stacksize=. stackframes
  21. ; mul stacksize can not be > 64k.
  22. ; 07/24/91 ToddLa. even newer stack switcher code! export StackEnter
  23. ; and StackLeave
  24. ; 11/02/92 StephenE. Hacked the code to make it work on NT/WOW.
  25. ;
  26. ;***************************************************************************;
  27. ifdef MYDEBUG
  28. DEBUG_RETAIL equ 1
  29. endif
  30. ?PLM=1 ; pascal call convention
  31. ?WIN=0 ; NO! Windows prolog/epilog code
  32. .286p
  33. .xlist
  34. include wow.inc
  35. include wowmmcb.inc
  36. include wowmmed.inc
  37. include cmacros.inc
  38. ; include windows.inc
  39. ; include mmsystem.inc
  40. ; include mmddk.inc
  41. ; include wowmmcb.inc
  42. include vint.inc
  43. .list
  44. OFFSEL STRUC
  45. Off dw ?
  46. Sel dw ?
  47. OFFSEL ENDS
  48. LOHI STRUC
  49. Lo dw ?
  50. Hi dw ?
  51. LOHI ENDS
  52. DCB_NOSWITCH equ 0008h ; don't switch stacks for callback
  53. DCB_TYPEMASK equ 0007h ; callback type mask
  54. DCB_NULL equ 0000h ; unknown callback type
  55. ; flags for wFlags parameter of DriverCallback()
  56. DCB_WINDOW equ 0001h ; dwCallback is a HWND
  57. DCB_TASK equ 0002h ; dwCallback is a HTASK
  58. DCB_FUNCTION equ 0003h ; dwCallback is a FARPROC
  59. externFP PostMessage ; in USER
  60. externFP PostAppMessage ; in USER
  61. externFP CALLPROC32W ; in Kernel
  62. externFP ThunkInit ; in init.c
  63. externFP WOW16Call ; in Kernel
  64. ;******************************************************************************
  65. ;
  66. ; SEGMENTS
  67. ;
  68. ;******************************************************************************
  69. createSeg FIX, CodeFix, word, public, CODE
  70. createSeg INTDS, DataFix, byte, public, DATA
  71. ;***************************************************************************;
  72. ;
  73. ; equates and structure definitions
  74. ;
  75. ;***************************************************************************;
  76. STACK_MAGIC equ 0BBADh
  77. ;***************************************************************************;
  78. ;
  79. ; Local data segment
  80. ;
  81. ;***************************************************************************;
  82. sBegin DataFix
  83. ;
  84. ; This is the stack we will switch to whenever we are calling
  85. ; a user call back
  86. ;
  87. public gwStackSize
  88. public gwStackFrames
  89. public gwStackUse
  90. public gwStackSelector
  91. public hdrvDestroy
  92. public vpCallbackData
  93. public hGlobal
  94. public DoInterrupt
  95. public tid32Message
  96. public mmwow32Lib
  97. public CheckThunkInit
  98. gwStackSize dw 0
  99. gwStackFrames dw 0
  100. gwStackUse dw 0
  101. gwStackSelector dw 0
  102. hdrvDestroy dw -1 ; this handle is being closed
  103. vpCallbackData dd 0
  104. hGlobal dd 0
  105. tid32Message dd 0 ; timer driver entry point
  106. mmwow32Lib dd 0
  107. sEnd DataFix
  108. ;-------------------------------------------------------------------------;
  109. ;
  110. ; debug support
  111. ;
  112. ;-------------------------------------------------------------------------;
  113. externFP OutputDebugString
  114. ;--------------------------Private-Macro----------------------------------;
  115. ; DOUT String - send a debug message to the debugger
  116. ;
  117. ; Entry:
  118. ; String String to send to the COM port, does not need a CR,LF
  119. ;
  120. ; Registers Destroyed:
  121. ; none
  122. ;
  123. ; NOTE no code is generated unless the MYDEBUG symbol is defined
  124. ;
  125. ; History:
  126. ; Sun 31-Jul-1989 -by- ToddLa
  127. ; Wrote it.
  128. ;-------------------------------------------------------------------------;
  129. DOUT macro text
  130. local string_buffer_stack
  131. ifdef MYDEBUG
  132. push cs
  133. push offset string_buffer_stack
  134. call OutputDebugString
  135. jmp @F
  136. string_buffer_stack label byte
  137. db "mmsystem: "
  138. db "&text&",13,10,0
  139. @@:
  140. endif
  141. endm
  142. ;***************************************************************************;
  143. ;
  144. ; code segment
  145. ;
  146. ;***************************************************************************;
  147. sBegin CodeFix
  148. assumes cs, CodeFix
  149. assumes ds, nothing
  150. assumes es, nothing
  151. externA __WinFlags
  152. public CodeFixWinFlags
  153. public CodeFixDS
  154. CodeFixWinFlags dw __WinFlags
  155. CodeFixDS dw DataFixBASE
  156. ;***************************************************************************;
  157. ;
  158. ; @doc DDK MMSYSTEM
  159. ;
  160. ; @asm StackEnter |
  161. ;
  162. ; This function switches to the next internal mmsystem interupt stack
  163. ; available.
  164. ;
  165. ; if one is not available we stay on the current stack.
  166. ;
  167. ; the size and number of mmsystem stacks is controlable from SYSTEM.INI
  168. ; (these are the defaults)
  169. ;
  170. ; [mmsystem]
  171. ; StackSize = 1536
  172. ; StackFrames = 3
  173. ;
  174. ; for every call to StackEnter a call to StackLeave *must* be made (even
  175. ; if StackEnter fails!)
  176. ;
  177. ; this function is intended to be used as the first thing done by a ISR
  178. ;
  179. ; MyISR proc far
  180. ;
  181. ; call StackEnter ; switch to a safe stack
  182. ;
  183. ; pusha ; save registers we use
  184. ;
  185. ; <handle IRQ>
  186. ;
  187. ; popa ; restore registers
  188. ;
  189. ; call StackLeave ; return to interupt stack
  190. ; iret ; done with ISR
  191. ;
  192. ; MyISR endp
  193. ;
  194. ; The old SS:SP is pushed onto the new stack, and the function returns.
  195. ;
  196. ; @rdesc NC ** succesfuly switced to a new stack
  197. ; C ** you are hosed jack, no stacks left
  198. ; (you remain on current stack)
  199. ;
  200. ; @uses flags
  201. ;
  202. ; @saves all
  203. ;
  204. ; @xref StackLeave, DriverCallback
  205. ;
  206. ;***************************************************************************;
  207. assumes ds, nothing
  208. assumes es, nothing
  209. cProc StackEnter, <FAR, PUBLIC>, <>
  210. cBegin nogen
  211. ;
  212. ; On WOW we only emulate Standard mode therefore I won't bother
  213. ; with the test described below.
  214. ;
  215. ; if we are in 386 mode or better (ie *not* standard mode) then, just
  216. ; get out.
  217. ;
  218. ; test cs:[CodeFixWinFlags],WF_WIN286
  219. ; jz stack_enter_retf
  220. push ds
  221. mov ds,[CodeFixDS]
  222. assumes ds,DataFix
  223. cmp [gwStackUse], 0 ; are we out of stacks?
  224. jne stack_enter_have_stack_will_travel ; ..no go grab it
  225. ;**********************************************************************-;
  226. ;
  227. ; We are out of internal stacks. To give us the greates chance
  228. ; of coming out of this condition alive, we stay on the current
  229. ; stack. This could fail miserably if we are on a very small
  230. ; stack**but it is better than crashing outright.
  231. ;
  232. ;**********************************************************************-;
  233. ifdef DEBUG_RETAIL
  234. cmp [gwStackSelector], 0
  235. je stack_enter_stay_here
  236. DOUT <StackEnter: All stacks in use, increase StackFrames>
  237. int 3
  238. endif
  239. ifdef MYDEBUG
  240. call dump_stack_users
  241. endif
  242. stack_enter_stay_here:
  243. pop ds
  244. assumes ds,nothing
  245. push bp
  246. mov bp,sp
  247. push ax
  248. xor ax,ax
  249. xchg [bp+4],ax
  250. xchg [bp+2],ax
  251. xchg [bp],ax
  252. xchg [bp-2],ax
  253. pop bp
  254. stack_enter_retf:
  255. stc
  256. retf
  257. ;**********************************************************************-;
  258. ;
  259. ; we have a stack to use, allocate stack FIRST, then muck with it
  260. ; leave no window for interrupts to blast us.
  261. ;
  262. ; It does this by using the contents of the gwStackUse variable as
  263. ; the new SP. This initially contains the address of the start (ie top)
  264. ; of the internal stack area, and is subtracted from each time a StackEnter
  265. ; occurs. It is of course added to again when StackLeave is called
  266. ; freeing up that area of stack for the next use.
  267. ;
  268. ; Note that the stack usage counter is modified before anything is
  269. ; is pushed onto the new stack. If an interrupt occurs after the stack
  270. ; switch, but before the usage is set, it will be fine.
  271. ;
  272. ;**********************************************************************-;
  273. assumes ds,DataFix
  274. stack_enter_have_stack_will_travel:
  275. push ax
  276. push bx
  277. mov bx,sp
  278. mov ax, [gwStackSize]
  279. sub [gwStackUse], ax ; reserve stack before using
  280. add ax, [gwStackUse] ; get current value and hang onto it
  281. ;**********************************************************************-;
  282. ;
  283. ; debug code, in the debug version we do crazy things like filling
  284. ; the stack with magic numbers.
  285. ;
  286. ;**********************************************************************-;
  287. ifdef MYDEBUG
  288. ; ** This code will fill the stack with the magic cookie**this
  289. ; ** is used to see how much stack space is being used at any
  290. ; ** time.
  291. push es
  292. push di
  293. push ax
  294. push cx
  295. mov di, ax ; es:di -> top of stack
  296. mov es, [gwStackSelector]
  297. mov cx, [gwStackSize] ; get size to fill
  298. sub di, cx ; es:di -> bottom of stack
  299. shr cx, 1 ; in words
  300. mov ax, STACK_MAGIC ; what to fill with
  301. cld ; bottom up
  302. rep stosw
  303. pop cx ; restore munged regs
  304. pop ax
  305. pop di
  306. pop es
  307. endif
  308. ifdef DEBUG_RETAIL
  309. ; ** This code puts a single magic cookie at the end of the stack.
  310. ; ** This is used by the stack leave routine to check for overflow.
  311. ; ** If the above code (the fill) is running, then this code is
  312. ; ** redundant.
  313. push es
  314. push bx
  315. mov es,[gwStackSelector]
  316. mov bx,[gwStackUse] ; new stack
  317. mov es:[bx], STACK_MAGIC
  318. pop bx
  319. pop es
  320. endif
  321. ;**********************************************************************-;
  322. ;
  323. ; time to switch to the *new* stack, [gwStackSelector]:AX contains
  324. ; the new SS:SP, but first save the *old* SS:SP and restore
  325. ; the registers we nuked to get here
  326. ;
  327. ;**********************************************************************-;
  328. push [gwStackSelector] ; push *new* ss
  329. push ss ; save current ss in ds
  330. pop ds
  331. assumes ds, nothing
  332. pop ss ; switch to new stack
  333. mov sp, ax ; ints off until after this on >= 286
  334. ;**********************************************************************-;
  335. ;
  336. ; now that we are on the new stack, copy some important info from
  337. ; the old stack to this one. note DS:[BX] points to the old stack
  338. ;
  339. ; [BX+0] ==> saved BX
  340. ; [BX+2] ==> saved AX
  341. ; [BX+4] ==> saved DS
  342. ; [BX+6] ==> return IP
  343. ; [BX+8] ==> return CS
  344. ;
  345. ; in the MYDEBUG version we save the callers CS:IP on the stack so we
  346. ; can (in dump_stack_users) walk all the stacks
  347. ;
  348. ;**********************************************************************-;
  349. ifdef MYDEBUG
  350. push [bx+8] ; push a CS:IP for dumping stack users
  351. push [bx+6]
  352. endif
  353. add bx,10 ; 10 = ax+bx+dx+retf
  354. push ds ; save old SS:SP (SP = BX+N)
  355. push bx
  356. sub bx,10
  357. push [bx+8] ; push return addr
  358. push [bx+6]
  359. push [bx+4] ; push saved DS
  360. push [bx] ; push saved BX
  361. mov ax,[bx+2] ; restore ax
  362. pop bx ; restore bx
  363. pop ds ; restore ds
  364. clc ; show success
  365. stack_leave_retf:
  366. retf ; return to caller
  367. cEnd nogen
  368. ;***************************************************************************;
  369. ;
  370. ; @doc DDK MMSYSTEM
  371. ;
  372. ; @asm StackLeave |
  373. ;
  374. ; This function returns the stack to the original stack saved by StackEnter
  375. ;
  376. ; @uses flags
  377. ;
  378. ; @saves all
  379. ;
  380. ; @xref StackEnter, DriverCallback
  381. ;
  382. ;***************************************************************************;
  383. assumes ds, nothing
  384. assumes es, nothing
  385. cProc StackLeave, <FAR, PUBLIC>, <>
  386. cBegin nogen
  387. ;
  388. ; if we are in 386 mode or better (ie *not* standard mode) then, just
  389. ; get out.
  390. ;
  391. ; test cs:[CodeFixWinFlags],WF_WIN286
  392. ; jz stack_leave_retf
  393. push bx
  394. mov bx,sp
  395. ;**********************************************************************-;
  396. ;
  397. ; here is the state of things:
  398. ;
  399. ; [BX+0] ==> saved BX
  400. ; [BX+2] ==> return IP
  401. ; [BX+4] ==> return CS
  402. ; [BX+6] ==> saved SP
  403. ; [BX+8] ==> saved SS
  404. ;
  405. ; the first thing we must check for is EnterStack running out of
  406. ; stacks. in this case StackEnter pushed a single zero where the
  407. ; saved SS should be
  408. ;
  409. ;**********************************************************************-;
  410. cmp word ptr ss:[bx+6],0 ; check saved SP
  411. jnz stack_leave_normal
  412. ;**********************************************************************-;
  413. ;
  414. ; StackEnter ran out of stacks, stay on the current stack, but remove
  415. ; the bogus SS
  416. ;
  417. ;**********************************************************************-;
  418. stack_leave_abby_normal:
  419. pop bx ; return to caller taking the
  420. retf 2 ; bogus zero SP with us
  421. ;**********************************************************************-;
  422. ;
  423. ; we need to return to the stack saved by StackEnter
  424. ;
  425. ;**********************************************************************-;
  426. stack_leave_normal:
  427. push ds ; [BX-2] ==> saved DS
  428. push ss ; DS = old stack
  429. pop ds
  430. assumes ds,nothing
  431. ifdef MYDEBUG
  432. push ax
  433. mov ax,[bx+8]
  434. lar ax,ax
  435. jz @f
  436. DOUT <StackLeave: invalid stack>
  437. int 3
  438. @@: pop ax
  439. endif
  440. mov ss,[bx+8] ; switch to new stack
  441. mov sp,[bx+6] ; ints off until after this on >= 286
  442. push [bx+4] ; push return addr
  443. push [bx+2]
  444. push [bx] ; push old BX
  445. push [bx-2] ; push old DS
  446. ;**********************************************************************-;
  447. ;
  448. ; we are back on the original stack, now it is time to deallocate
  449. ; the stack.
  450. ;
  451. ; The stack usage must only be released after all
  452. ; values have been removed from the stack so that an interrupt can be
  453. ; serviced without writing over any values.
  454. ;
  455. ;**********************************************************************-;
  456. mov ds,[CodeFixDS] ; get at our globals
  457. assumes ds,DataFix
  458. ifdef DEBUG_RETAIL
  459. push es
  460. push bx
  461. mov bx,[gwStackUse] ; before we release it
  462. mov es,[gwStackSelector]
  463. cmp es:[bx], STACK_MAGIC
  464. mov es:[bx], STACK_MAGIC ; and try to recover...
  465. pop bx
  466. pop es
  467. je @f ; true if magic cookie existed
  468. DOUT <StackLeave: STACK OVERFLOW>
  469. int 3
  470. ifdef MYDEBUG
  471. call dump_stack_users
  472. endif
  473. @@:
  474. endif
  475. mov bx, [gwStackSize] ; get the size of the stacks
  476. add [gwStackUse], bx ; release stack frame after use
  477. pop ds
  478. assumes ds,nothing
  479. pop bx
  480. retf
  481. cEnd nogen
  482. ;****************************************************************************
  483. ; FUNCTION: DoInterrupt()
  484. ;
  485. ; PURPOSE:
  486. ; This routine is called by the ISR in the InstallInerruptHandler
  487. ; routine.
  488. ;
  489. ; void DoInterrupt( void )
  490. ; {
  491. ; VPCALLBACK_ARGS pArgs;
  492. ; WORD wSendCount = vpCallbackData->wSendCount;
  493. ; WORD wTempRecvCount;
  494. ;
  495. ; /*
  496. ; ** At entry to this function the receive count should be one less than
  497. ; ** than the send count. However, it is possible that we have lost some
  498. ; ** interrupts in which case we should try to "catch up" here.
  499. ; **
  500. ; ** The 32 bit side does not increament wSendCount until the
  501. ; ** callback data buffer has been updated. This means that although it
  502. ; ** is possible that it could have been changed before this interrupt
  503. ; ** was generated it will never point to an invalid buffer location.
  504. ; ** We simply process two interrupt request from the first interrupt,
  505. ; ** when the second interrupt goes off we return straight away.
  506. ; */
  507. ; vpCallbackData->wIntsCount++;
  508. ;
  509. ; while ( vpCallbackData->wRecvCount != wSendCount ) {
  510. ;
  511. ; /*
  512. ; ** Increment the recv count. Use of the % operator to makes sure
  513. ; ** that we wrap around to the begining of the array correctly.
  514. ; */
  515. ; wTempRecvCount = (vpCallbackData->wRecvCount + 1)
  516. ; % CALLBACK_ARGS_SIZE;
  517. ;
  518. ; pArgs = &vpCallbackData->args[ wTempRecvCount ];
  519. ; DriverCallback( pArgs->dwFunctionAddr,
  520. ; LOWORD( pArgs->dwFlags ),
  521. ; pArgs->wHandle,
  522. ; pArgs->wMessage,
  523. ; pArgs->dwInstance,
  524. ; pArgs->dwParam1,
  525. ; pArgs->dwParam2 );
  526. ;
  527. ; vpCallbackData->wRecvCount = wTempRecvCount;
  528. ; }
  529. ;
  530. ; }
  531. ;
  532. ;****************************************************************************
  533. cProc DoInterrupt, <FAR,PUBLIC>, <si,di>
  534. localW wSendCount ;number of interrupts sent
  535. cBegin DoInt
  536. DOUT <Multi-Media Interupt called>
  537. ;
  538. ; Now we take the parameters from the global callback data array
  539. ; and increment the dwRecvCount field. Then we make the
  540. ; callback into the apps routine. Note that the es:bx registers are used
  541. ; instead of the local variable pArgs.
  542. ;
  543. mov es,[CodeFixDS]
  544. assumes es,DataFix
  545. ;
  546. ; wSendCount = vpCallbackData->wSendCount
  547. ; vpCallbackData->wIntsCount++;
  548. ;
  549. les bx,DWORD PTR es:vpCallbackData
  550. mov ax,WORD PTR es:[bx+2]
  551. mov wSendCount,ax
  552. inc WORD PTR es:[bx+388] ; increment the count of interrupts rcv
  553. jmp DoIntMakeTheTest
  554. ;
  555. ; Make es:bx point to the correct slot in the callback data table.
  556. ;
  557. DoIntMakeTheCall:
  558. ;
  559. ; Increment the recv count. Use of the % operator above makes sure
  560. ; that we wrap around to the begining of the array correctly.
  561. ;
  562. ; wTempRecvCount = (vpCallbackData->wRecvCount + 1) % CALLBACK_ARGS_SIZE;
  563. ;
  564. mov al,BYTE PTR es:[bx]
  565. inc al
  566. and ax,15
  567. mov cx,ax
  568. ;
  569. ; pArgs = &vpCallbackData->args[ vpCallbackData->wRecvCount ];
  570. ; vpCallbackData->wRecvCount = wTempRecvCount;
  571. ; Note that pArgs is really es:bx.
  572. ;
  573. mov es,[CodeFixDS]
  574. les bx,DWORD PTR es:vpCallbackData
  575. imul ax,WORD PTR es:[bx],24 ;ax = wRecvCount * sizeof(CALLBACKDATA)
  576. ;
  577. ; Note: our caller saves ALL registers. We do not need to preserve si
  578. ;
  579. mov si,bx
  580. add bx,ax ;bx = bx + ax
  581. add bx,4 ;bx += sizeof(WORD) * 2
  582. ;
  583. ; Set up the stack frame for DriverCallback
  584. ;
  585. push WORD PTR es:[bx+6]
  586. push WORD PTR es:[bx+4]
  587. push WORD PTR es:[bx]
  588. push WORD PTR es:[bx+8]
  589. push WORD PTR es:[bx+10]
  590. push WORD PTR es:[bx+14]
  591. push WORD PTR es:[bx+12]
  592. push WORD PTR es:[bx+18]
  593. push WORD PTR es:[bx+16]
  594. push WORD PTR es:[bx+22]
  595. push WORD PTR es:[bx+20]
  596. ;
  597. ; We have to set up the stack frame before incrementing wRecvCount to
  598. ; prevent the 32 bit code from eating our slot in the buffer.
  599. ;
  600. mov WORD PTR es:[si],cx ;wRecvCount = wTempRecvCount
  601. call FAR PTR DriverCallback
  602. ;
  603. ; Reload es:bx and ax ready for the loop test
  604. ;
  605. mov ax,wSendCount
  606. mov es,[CodeFixDS]
  607. les bx,DWORD PTR es:vpCallbackData
  608. DoIntMakeTheTest:
  609. cmp WORD PTR es:[bx],ax
  610. jne DoIntMakeTheCall
  611. cEnd DoInt
  612. ifdef XDEBUG
  613. public stack_enter_stay_here
  614. public stack_enter_have_stack_will_travel
  615. public stack_leave_abby_normal
  616. public stack_leave_normal
  617. endif
  618. ;***************************************************************************;
  619. ;
  620. ; @doc DDK MMSYSTEM
  621. ;
  622. ; @api BOOL | DriverCallback | This function notifies a client
  623. ; application by sending a message to a window or callback
  624. ; function or by unblocking a task.
  625. ;
  626. ; @parm DWORD | dwCallBack | Specifies either the address of
  627. ; a callback function, a window handle, or a task handle, depending on
  628. ; the flags specified in the <p wFlags> parameter.
  629. ;
  630. ; @parm WORD | wFlags | Specifies how the client
  631. ; application is notified, according to one of the following flags:
  632. ;
  633. ; @flag DCB_FUNCTION | The application is notified by
  634. ; sending a message to a callback function. The <p dwCallback>
  635. ; parameter specifies a procedure-instance address.
  636. ; @flag DCB_WINDOW | The application is notified by
  637. ; sending a message to a window. The low-order word of the
  638. ; <p dwCallback> parameter specifies a window handle.
  639. ;
  640. ; @flag DCB_NOSWITCH | DriverCallback should *not* switch to a new stack
  641. ;
  642. ; @parm WORD | hDevice | Specifies a handle to the device
  643. ; associated with the notification. This is the handle assigned by
  644. ; MMSYSTEM when the device was opened.
  645. ;
  646. ; @parm WORD | wMsg | Specifies a message to send to the
  647. ; application.
  648. ;
  649. ; @parm DWORD | dwUser | Specifies the DWORD of user instance
  650. ; data supplied by the application when the device was opened.
  651. ;
  652. ; @parm DWORD | dwParam1 | Specifies a message-dependent parameter.
  653. ; @parm DWORD | dwParam2 | Specifies a message-dependent parameter.
  654. ;
  655. ; @rdesc Returns TRUE if the callback was performed, else FALSE if an invalid
  656. ; parameter was passed, or the task's message queue was full.
  657. ;
  658. ; @comm This function can be called at interrupt time.
  659. ;
  660. ; The flags DCB_FUNCTION and DCB_WINDOW are equivalent to the
  661. ; high-order word of the corresponding flags CALLBACK_FUNCTION
  662. ; and CALLBACK_WINDOW specified when the device was opened.
  663. ;
  664. ; If notification is done with a callback function, <p hDevice>,
  665. ; <p wMsg>, <p dwUser>, <p dwParam1>, and <p dwParam2> are passed to
  666. ; the callback. If notification is done with a window, only <p wMsg>,
  667. ; <p hDevice>, and <p dwParam1> are passed to the window.
  668. ;***************************************************************************;
  669. assumes ds, nothing
  670. assumes es, nothing
  671. cProc DriverCallback, <FAR, PASCAL, PUBLIC>, <>
  672. parmD dwCallBack ; callback procedure to call
  673. parmW fCallBack ; callback flags
  674. parmW hdrv ; handle to the driver
  675. parmW msg ; driver message
  676. parmD dwUser ; user instance data
  677. parmD dw1 ; message specific
  678. parmD dw2 ; message specific
  679. cBegin
  680. cld ; lets not make any assumptions about this!!!!
  681. ;**************************************************************************-;
  682. ; check for quick exit cases and get out fast
  683. ;**************************************************************************-;
  684. mov ax,dwCallback.lo ; check for dwCallback == NULL
  685. or ax,dwCallback.hi
  686. jz dcb_error_exit_now ; if NULL get out fast
  687. mov ax,fCallback ; get flags and mask out the type bits
  688. test ax,DCB_TYPEMASK
  689. jz dcb_error_exit_now ; if NULL get out fast
  690. ifdef NEVER
  691. ;**************************************************************************-;
  692. ; if this handle is being NUKED don't allow callbacks into the app
  693. ;
  694. ; I won't bother with this test on WOW either. -- StephenE 2nd Nov 1992
  695. ;**************************************************************************-;
  696. mov es,[CodeFixDS]
  697. assumes es,DataFix
  698. mov bx,hdrv
  699. cmp bx,es:[hdrvDestroy] ; same as the handle being nuked?
  700. je dcb_error_exit_now ; if yes, get out'a here
  701. assumes es,nothing
  702. endif
  703. ;**************************************************************************-;
  704. ; set up ES == SS, so we can access stack params after switching
  705. ; stacks, NOTE!! ES:[bp+##] *must* be used to access parameters!
  706. ;**************************************************************************-;
  707. mov cx,ss ; set ES == callers stack
  708. mov es,cx ; use ES to get at local vars
  709. assumes es,nothing
  710. ;**************************************************************************-;
  711. ; We won't switch stacks on WOW since DPMI does this for us. Win 3.1
  712. ; would only switch stacks in Standard mode which we no longer support.
  713. ;**************************************************************************-;
  714. ; test ax,DCB_NOSWITCH ; should we switch stacks?
  715. ; jnz dcb_on_stack
  716. ; call StackEnter ; switch to new stack
  717. ;**************************************************************************-;
  718. ; determine the type of the callback, dwCallback is either a FARPROC, HWND
  719. ; or HTASK depending on the value of fCallback
  720. ;**************************************************************************-;
  721. dcb_on_stack:
  722. ;
  723. pushf ; Save the interrupt flag state
  724. FSTI ; ** Enable interrupts here **
  725. ;
  726. ; push ax ; save flags for StackLeave test
  727. and ax,DCB_TYPEMASK ; mask out the type bits
  728. cmp ax,DCB_WINDOW ; is it a window handle?
  729. je dcb_post_message
  730. cmp ax,DCB_TASK ; is it a task handle?
  731. je dcb_post_event
  732. cmp ax,DCB_FUNCTION ; is it a procedure?
  733. je dcb_call_callback
  734. DOUT <DriverCallback: Invalid flags #ax>
  735. xor ax,ax
  736. jmp dcb_exit
  737. dcb_error_exit_now:
  738. xor ax,ax
  739. jmp dcb_exit_now
  740. ifdef NEVER
  741. ;**************************************************************************-;
  742. ; the Callback flags are NULL determine the callback type by the HIWORD
  743. ; of dwCallback, if it is NULL assume it is a WINDOW otherwise it is a
  744. ; FARPROC
  745. ;**************************************************************************-;
  746. dcb_null_flags:
  747. mov ax,es:dwCallback.hi ; get selector of callback
  748. or ax,ax
  749. jnz dcb_call_callback ; if NULL then assume it is a window
  750. errn$ dcb_post_message ; otherwise assume a FARPROC
  751. endif
  752. ;**************************************************************************-;
  753. ; dwCallback is a window handle, call PostMessage() to insert a message in
  754. ; the applications message Que
  755. ;**************************************************************************-;
  756. dcb_post_event:
  757. cmc
  758. dcb_post_message:
  759. push es:dwCallback.lo ; hwnd
  760. push es:msg ; message
  761. push es:hdrv ; wParam = hdrv
  762. push es:dw1.hi ; lParam = dw1
  763. push es:dw1.lo
  764. jc dcb_post_app_message
  765. call PostMessage
  766. jmp dcb_exit
  767. ;**************************************************************************-;
  768. ; dwCallback is a task handle, call PostAppMessage() to 'wake' the task up
  769. ;**************************************************************************-;
  770. dcb_post_app_message:
  771. call PostAppMessage
  772. jmp dcb_exit
  773. ;**************************************************************************-;
  774. ; dwCallback is a callback procedure, we will call it.
  775. ;**************************************************************************-;
  776. dcb_call_callback:
  777. ;
  778. ; is the callback a valid function?
  779. ;
  780. lar ax,es:dwCallback.hi
  781. jnz dcb_invalid_callback
  782. test ax,0800H ; test for code/data selector
  783. jnz dcb_valid_callback
  784. dcb_invalid_callback:
  785. ifdef MYDEBUG_RETAIL
  786. mov ax,es:dwCallback.lo
  787. mov dx,es:dwCallback.hi
  788. DOUT <DriverCallback: Invalid callback function #dx:#ax>
  789. int 3
  790. endif
  791. xor ax,ax
  792. jmp dcb_exit
  793. dcb_valid_callback:
  794. push es:hdrv
  795. push es:msg
  796. push es:dwUser.hi
  797. push es:dwUser.lo
  798. push es:dw1.hi
  799. push es:dw1.lo
  800. push es:dw2.hi
  801. push es:dw2.lo
  802. call es:dwCallback
  803. mov ax,1
  804. errn$ dcb_exit
  805. dcb_exit:
  806. ;
  807. popf ; ** restore the interrupt flag **
  808. ;
  809. ; pop bx ; restore flags
  810. ; test bx,DCB_NOSWITCH ; should we switch back?
  811. ; jnz dcb_exit_now
  812. ; call StackLeave ; return to previous stack
  813. errn$ dcb_exit_now
  814. dcb_exit_now:
  815. cEnd
  816. ifdef MYDEBUG
  817. ;**************************************************************************-;
  818. ;
  819. ; each mmsystem stack has a SS:SP and in MYDEBUG a CS:IP of the caller of
  820. ; StackEnter, the top of each stack looks like this.
  821. ;
  822. ; +-------------------------------------+
  823. ; | CS:IP of caller of StackEnter() (in MYDEBUG)
  824. ; +-------------------------------------+
  825. ; | SS:SP to restore
  826. ; +-------------------------------------+
  827. ;
  828. ;**************************************************************************-;
  829. assumes ds,DataFix
  830. assumes es,nothing
  831. public dump_stack_users
  832. dump_stack_users proc near
  833. cmp [gwStackSelector],0
  834. jne @f
  835. ret
  836. @@: pusha
  837. push es
  838. mov cx,[gwStackFrames]
  839. mov di,[gwStackSize]
  840. mov si,[gwStackUse]
  841. mov es,gwStackSelector
  842. DOUT <StackUsers: Frames[#cx] Size[#di] Use[#si]>
  843. dump_stack_loop:
  844. lar ax,es:[di-4].sel
  845. jnz dump_stack_next
  846. mov ax,es:[di-4].off ; get CS:IP of StackEnter caller
  847. mov dx,es:[di-4].sel
  848. mov si,es:[di-8].off ; get SS:SP of StackEnter caller
  849. mov bx,es:[di-8].sel
  850. DOUT <StackUser #cx is CS:IP = #dx:#ax SS:SP = #bx:#si>
  851. dump_stack_next:
  852. add di,[gwStackSize]
  853. loop dump_stack_loop
  854. pop es
  855. popa
  856. ret
  857. dump_stack_users endp
  858. endif
  859. ;-----------------------------------------------------------------------;
  860. ;
  861. ; @doc INTERNAL
  862. ;
  863. ; @api DWORD | CheckThunkInit | send a message to the timer driver
  864. ;
  865. ; @rdesc Returns 0 if successful, otherwise an error code,
  866. ; (typically MMSYSERR_NODRIVER).
  867. ;
  868. ;-----------------------------------------------------------------------;
  869. assumes ds,nothing
  870. assumes es,nothing
  871. cProc CheckThunkInit, <FAR, PUBLIC, PASCAL>, <>
  872. cBegin
  873. mov es,[CodeFixDS]
  874. assumes es,DataFix
  875. sub ax,ax ; assume sucess
  876. mov bx,WORD PTR es:[mmwow32Lib] ; is mmwow32Lib loaded ?
  877. mov cx,WORD PTR es:[mmwow32Lib+2] ; try to load it
  878. or cx,bx ; ThunkInit returns ax=1
  879. jnz @F ; if it loaded OK, otherwise
  880. call ThunkInit ; ax=MMSYSERR_NODRIVER
  881. @@:
  882. cEnd
  883. ;-----------------------------------------------------------------------;
  884. ;
  885. ; @doc INTERNAL
  886. ;
  887. ; @api DWORD | timeMessage | send a message to the timer driver
  888. ;
  889. ; @parm WORD | msg | message to send
  890. ;
  891. ; @parm DWORD | dw1 | first DWORD
  892. ;
  893. ; @parm DWORD | dw2 | first DWORD
  894. ;
  895. ; @rdesc Returns zero if successful, error code otherwise
  896. ;
  897. ;-----------------------------------------------------------------------;
  898. assumes ds,nothing
  899. assumes es,nothing
  900. cProc timeMessage, <FAR, PUBLIC, PASCAL>, <>
  901. ParmW msg
  902. ParmD dw1
  903. ParmD dw2
  904. cBegin
  905. mov es,[CodeFixDS]
  906. assumes es,DataFix
  907. sub ax,ax ; assume sucess
  908. mov bx,WORD PTR es:[mmwow32Lib] ; is mmwow32Lib loaded ?
  909. mov cx,WORD PTR es:[mmwow32Lib+2] ; try to load it
  910. or cx,bx ; ThunkInit returns ax=1
  911. jnz timer_have_thunks ; if it loaded OK, otherwise
  912. push es
  913. call ThunkInit ; ax=MMSYSERR_NODRIVER
  914. pop es
  915. or ax,ax
  916. jnz timeMessageExit
  917. timer_have_thunks:
  918. push ax ; uDevID
  919. push ax ;
  920. push ax ; Message passed
  921. push msg ;
  922. push ax ; dwInstance
  923. push ax ;
  924. push dw1.hi ; dwParam1
  925. push dw1.lo ;
  926. push dw2.hi ; dwParam2
  927. push dw2.lo ;
  928. push WORD PTR es:[tid32Message+2] ; Address of function to call
  929. push WORD PTR es:[tid32Message] ;
  930. push ax ; No directory change
  931. push ax
  932. call FAR PTR MMCALLPROC32
  933. timeMessageExit:
  934. cEnd
  935. MMediaThunk MMCALLPROC32
  936. sEnd CodeFix
  937. end