TASK_MAN.C 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977
  1. /*
  2. Copyright (C) 1994-1995 Apogee Software, Ltd.
  3. This program is free software; you can redistribute it and/or
  4. modify it under the terms of the GNU General Public License
  5. as published by the Free Software Foundation; either version 2
  6. of the License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. See the GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  14. */
  15. /**********************************************************************
  16. module: TASK_MAN.C
  17. author: James R. Dose
  18. date: July 25, 1994
  19. Low level timer task scheduler.
  20. (c) Copyright 1994 James R. Dose. All Rights Reserved.
  21. **********************************************************************/
  22. #define TRUE ( 1 == 1 )
  23. #define FALSE ( !TRUE )
  24. //#define USESTACK
  25. #define LOCKMEMORY
  26. #define NOINTS
  27. #define USE_USRHOOKS
  28. #include <stdlib.h>
  29. #include <dos.h>
  30. #include <conio.h>
  31. #include <string.h>
  32. #include "interrup.h"
  33. #include "linklist.h"
  34. #include "task_man.h"
  35. #ifdef USESTACK
  36. #include "dpmi.h"
  37. #endif
  38. #ifdef LOCKMEMORY
  39. #include "dpmi.h"
  40. #endif
  41. #ifdef USE_USRHOOKS
  42. #include "usrhooks.h"
  43. #define FreeMem( ptr ) USRHOOKS_FreeMem( ( ptr ) )
  44. #else
  45. #define FreeMem( ptr ) free( ( ptr ) )
  46. #endif
  47. typedef struct
  48. {
  49. task *start;
  50. task *end;
  51. } tasklist;
  52. /*---------------------------------------------------------------------
  53. Global variables
  54. ---------------------------------------------------------------------*/
  55. #ifdef USESTACK
  56. // adequate stack size
  57. #define kStackSize 2048
  58. static unsigned short StackSelector = NULL;
  59. static unsigned long StackPointer;
  60. static unsigned short oldStackSelector;
  61. static unsigned long oldStackPointer;
  62. #endif
  63. static task HeadTask;
  64. static task *TaskList = &HeadTask;
  65. static void ( __interrupt __far *OldInt8 )( void );
  66. static volatile long TaskServiceRate = 0x10000L;
  67. static volatile long TaskServiceCount = 0;
  68. #ifndef NOINTS
  69. static volatile int TS_TimesInInterrupt;
  70. #endif
  71. static char TS_Installed = FALSE;
  72. volatile int TS_InInterrupt = FALSE;
  73. /*---------------------------------------------------------------------
  74. Function prototypes
  75. ---------------------------------------------------------------------*/
  76. static void TS_FreeTaskList( void );
  77. static void TS_SetClockSpeed( long speed );
  78. static long TS_SetTimer( long TickBase );
  79. static void TS_SetTimerToMaxTaskRate( void );
  80. static void __interrupt __far TS_ServiceSchedule( void );
  81. static void __interrupt __far TS_ServiceScheduleIntEnabled( void );
  82. static void TS_AddTask( task *ptr );
  83. static int TS_Startup( void );
  84. static void RestoreRealTimeClock( void );
  85. // These declarations are necessary to use the inline assembly pragmas.
  86. extern void GetStack(unsigned short *selptr,unsigned long *stackptr);
  87. extern void SetStack(unsigned short selector,unsigned long stackptr);
  88. // This function will get the current stack selector and pointer and save
  89. // them off.
  90. #pragma aux GetStack = \
  91. "mov [edi],esp" \
  92. "mov ax,ss" \
  93. "mov [esi],ax" \
  94. parm [esi] [edi] \
  95. modify [eax esi edi];
  96. // This function will set the stack selector and pointer to the specified
  97. // values.
  98. #pragma aux SetStack = \
  99. "mov ss,ax" \
  100. "mov esp,edx" \
  101. parm [ax] [edx] \
  102. modify [eax edx];
  103. /**********************************************************************
  104. Memory locked functions:
  105. **********************************************************************/
  106. #define TS_LockStart TS_FreeTaskList
  107. /*---------------------------------------------------------------------
  108. Function: TS_FreeTaskList
  109. Terminates all tasks and releases any memory used for control
  110. structures.
  111. ---------------------------------------------------------------------*/
  112. static void TS_FreeTaskList
  113. (
  114. void
  115. )
  116. {
  117. task *node;
  118. task *next;
  119. unsigned flags;
  120. flags = DisableInterrupts();
  121. node = TaskList->next;
  122. while( node != TaskList )
  123. {
  124. next = node->next;
  125. FreeMem( node );
  126. node = next;
  127. }
  128. TaskList->next = TaskList;
  129. TaskList->prev = TaskList;
  130. RestoreInterrupts( flags );
  131. }
  132. /*---------------------------------------------------------------------
  133. Function: TS_SetClockSpeed
  134. Sets the rate of the 8253 timer.
  135. ---------------------------------------------------------------------*/
  136. static void TS_SetClockSpeed
  137. (
  138. long speed
  139. )
  140. {
  141. unsigned flags;
  142. flags = DisableInterrupts();
  143. if ( ( speed > 0 ) && ( speed < 0x10000L ) )
  144. {
  145. TaskServiceRate = speed;
  146. }
  147. else
  148. {
  149. TaskServiceRate = 0x10000L;
  150. }
  151. outp( 0x43, 0x36 );
  152. outp( 0x40, TaskServiceRate );
  153. outp( 0x40, TaskServiceRate >> 8 );
  154. RestoreInterrupts( flags );
  155. }
  156. /*---------------------------------------------------------------------
  157. Function: TS_SetTimer
  158. Calculates the rate at which a task will occur and sets the clock
  159. speed if necessary.
  160. ---------------------------------------------------------------------*/
  161. static long TS_SetTimer
  162. (
  163. long TickBase
  164. )
  165. {
  166. long speed;
  167. speed = 1192030L / TickBase;
  168. if ( speed < TaskServiceRate )
  169. {
  170. TS_SetClockSpeed( speed );
  171. }
  172. return( speed );
  173. }
  174. /*---------------------------------------------------------------------
  175. Function: TS_SetTimerToMaxTaskRate
  176. Finds the fastest running task and sets the clock to operate at
  177. that speed.
  178. ---------------------------------------------------------------------*/
  179. static void TS_SetTimerToMaxTaskRate
  180. (
  181. void
  182. )
  183. {
  184. task *ptr;
  185. long MaxServiceRate;
  186. unsigned flags;
  187. flags = DisableInterrupts();
  188. MaxServiceRate = 0x10000L;
  189. ptr = TaskList->next;
  190. while( ptr != TaskList )
  191. {
  192. if ( ptr->rate < MaxServiceRate )
  193. {
  194. MaxServiceRate = ptr->rate;
  195. }
  196. ptr = ptr->next;
  197. }
  198. if ( TaskServiceRate != MaxServiceRate )
  199. {
  200. TS_SetClockSpeed( MaxServiceRate );
  201. }
  202. RestoreInterrupts( flags );
  203. }
  204. #ifdef NOINTS
  205. /*---------------------------------------------------------------------
  206. Function: TS_ServiceSchedule
  207. Interrupt service routine
  208. ---------------------------------------------------------------------*/
  209. static void __interrupt __far TS_ServiceSchedule
  210. (
  211. void
  212. )
  213. {
  214. task *ptr;
  215. task *next;
  216. TS_InInterrupt = TRUE;
  217. #ifdef USESTACK
  218. // save stack
  219. GetStack( &oldStackSelector, &oldStackPointer );
  220. // set our stack
  221. SetStack( StackSelector, StackPointer );
  222. #endif
  223. ptr = TaskList->next;
  224. while( ptr != TaskList )
  225. {
  226. next = ptr->next;
  227. if ( ptr->active )
  228. {
  229. ptr->count += TaskServiceRate;
  230. //JIM
  231. // if ( ptr->count >= ptr->rate )
  232. while( ptr->count >= ptr->rate )
  233. {
  234. ptr->count -= ptr->rate;
  235. ptr->TaskService( ptr );
  236. }
  237. }
  238. ptr = next;
  239. }
  240. #ifdef USESTACK
  241. // restore stack
  242. SetStack( oldStackSelector, oldStackPointer );
  243. #endif
  244. TaskServiceCount += TaskServiceRate;
  245. if ( TaskServiceCount > 0xffffL )
  246. {
  247. TaskServiceCount &= 0xffff;
  248. _chain_intr( OldInt8 );
  249. }
  250. outp( 0x20,0x20 );
  251. TS_InInterrupt = FALSE;
  252. }
  253. #else
  254. /*---------------------------------------------------------------------
  255. Function: TS_ServiceScheduleIntEnabled
  256. Interrupt service routine with interrupts enabled.
  257. ---------------------------------------------------------------------*/
  258. static void __interrupt __far TS_ServiceScheduleIntEnabled
  259. (
  260. void
  261. )
  262. {
  263. task *ptr;
  264. task *next;
  265. TS_TimesInInterrupt++;
  266. TaskServiceCount += TaskServiceRate;
  267. if ( TaskServiceCount > 0xffffL )
  268. {
  269. TaskServiceCount &= 0xffff;
  270. _chain_intr( OldInt8 );
  271. }
  272. outp( 0x20,0x20 );
  273. if ( TS_InInterrupt )
  274. {
  275. return;
  276. }
  277. TS_InInterrupt = TRUE;
  278. _enable();
  279. #ifdef USESTACK
  280. // save stack
  281. GetStack( &oldStackSelector, &oldStackPointer );
  282. // set our stack
  283. SetStack( StackSelector, StackPointer );
  284. #endif
  285. while( TS_TimesInInterrupt )
  286. {
  287. ptr = TaskList->next ;
  288. while( ptr != TaskList )
  289. {
  290. next = ptr->next;
  291. if ( ptr->active )
  292. {
  293. ptr->count += TaskServiceRate;
  294. if ( ptr->count >= ptr->rate )
  295. {
  296. ptr->count -= ptr->rate;
  297. ptr->TaskService( ptr );
  298. }
  299. }
  300. ptr = next;
  301. }
  302. TS_TimesInInterrupt--;
  303. }
  304. _disable();
  305. #ifdef USESTACK
  306. // restore stack
  307. SetStack( oldStackSelector, oldStackPointer );
  308. #endif
  309. TS_InInterrupt = FALSE;
  310. }
  311. #endif
  312. #ifdef USESTACK
  313. /*---------------------------------------------------------------------
  314. Function: allocateTimerStack
  315. Allocate a block of memory from conventional (low) memory and return
  316. the selector (which can go directly into a segment register) of the
  317. memory block or 0 if an error occured.
  318. ---------------------------------------------------------------------*/
  319. static unsigned short allocateTimerStack
  320. (
  321. unsigned short size
  322. )
  323. {
  324. union REGS regs;
  325. // clear all registers
  326. memset( &regs, 0, sizeof( regs ) );
  327. // DPMI allocate conventional memory
  328. regs.w.ax = 0x100;
  329. // size in paragraphs
  330. regs.w.bx = ( size + 15 ) / 16;
  331. int386( 0x31, &regs, &regs );
  332. if (!regs.w.cflag)
  333. {
  334. // DPMI call returns selector in dx
  335. // (ax contains real mode segment
  336. // which is ignored here)
  337. return( regs.w.dx );
  338. }
  339. // Couldn't allocate memory.
  340. return( NULL );
  341. }
  342. /*---------------------------------------------------------------------
  343. Function: deallocateTimerStack
  344. Deallocate a block of conventional (low) memory given a selector to
  345. it. Assumes the block was allocated with DPMI function 0x100.
  346. ---------------------------------------------------------------------*/
  347. static void deallocateTimerStack
  348. (
  349. unsigned short selector
  350. )
  351. {
  352. union REGS regs;
  353. if ( selector != NULL )
  354. {
  355. // clear all registers
  356. memset( &regs, 0, sizeof( regs ) );
  357. regs.w.ax = 0x101;
  358. regs.w.dx = selector;
  359. int386( 0x31, &regs, &regs );
  360. }
  361. }
  362. #endif
  363. /*---------------------------------------------------------------------
  364. Function: TS_Startup
  365. Sets up the task service routine.
  366. ---------------------------------------------------------------------*/
  367. static int TS_Startup
  368. (
  369. void
  370. )
  371. {
  372. if ( !TS_Installed )
  373. {
  374. #ifdef LOCKMEMORY
  375. int status;
  376. status = TS_LockMemory();
  377. if ( status != TASK_Ok )
  378. {
  379. TS_UnlockMemory();
  380. return( status );
  381. }
  382. #endif
  383. #ifdef USESTACK
  384. StackSelector = allocateTimerStack( kStackSize );
  385. if ( StackSelector == NULL )
  386. {
  387. #ifdef LOCKMEMORY
  388. TS_UnlockMemory();
  389. #endif
  390. return( TASK_Error );
  391. }
  392. // Leave a little room at top of stack just for the hell of it...
  393. StackPointer = kStackSize - sizeof( long );
  394. #endif
  395. //static const task *TaskList = &HeadTask;
  396. TaskList->next = TaskList;
  397. TaskList->prev = TaskList;
  398. TaskServiceRate = 0x10000L;
  399. TaskServiceCount = 0;
  400. #ifndef NOINTS
  401. TS_TimesInInterrupt = 0;
  402. #endif
  403. OldInt8 = _dos_getvect( 0x08 );
  404. #ifdef NOINTS
  405. _dos_setvect( 0x08, TS_ServiceSchedule );
  406. #else
  407. _dos_setvect( 0x08, TS_ServiceScheduleIntEnabled );
  408. #endif
  409. TS_Installed = TRUE;
  410. }
  411. return( TASK_Ok );
  412. }
  413. /*---------------------------------------------------------------------
  414. Function: TS_Shutdown
  415. Ends processing of all tasks.
  416. ---------------------------------------------------------------------*/
  417. void TS_Shutdown
  418. (
  419. void
  420. )
  421. {
  422. if ( TS_Installed )
  423. {
  424. TS_FreeTaskList();
  425. TS_SetClockSpeed( 0 );
  426. _dos_setvect( 0x08, OldInt8 );
  427. #ifdef USESTACK
  428. deallocateTimerStack( StackSelector );
  429. StackSelector = NULL;
  430. #endif
  431. // Set Date and Time from CMOS
  432. // RestoreRealTimeClock();
  433. #ifdef LOCKMEMORY
  434. TS_UnlockMemory();
  435. #endif
  436. TS_Installed = FALSE;
  437. }
  438. }
  439. /*---------------------------------------------------------------------
  440. Function: TS_ScheduleTask
  441. Schedules a new task for processing.
  442. ---------------------------------------------------------------------*/
  443. task *TS_ScheduleTask
  444. (
  445. void ( *Function )( task * ),
  446. int rate,
  447. int priority,
  448. void *data
  449. )
  450. {
  451. task *ptr;
  452. #ifdef USE_USRHOOKS
  453. int status;
  454. ptr = NULL;
  455. status = USRHOOKS_GetMem( &ptr, sizeof( task ) );
  456. if ( status == USRHOOKS_Ok )
  457. #else
  458. ptr = malloc( sizeof( task ) );
  459. if ( ptr != NULL )
  460. #endif
  461. {
  462. if ( !TS_Installed )
  463. {
  464. status = TS_Startup();
  465. if ( status != TASK_Ok )
  466. {
  467. FreeMem( ptr );
  468. return( NULL );
  469. }
  470. }
  471. ptr->TaskService = Function;
  472. ptr->data = data;
  473. ptr->rate = TS_SetTimer( rate );
  474. ptr->count = 0;
  475. ptr->priority = priority;
  476. ptr->active = FALSE;
  477. TS_AddTask( ptr );
  478. }
  479. return( ptr );
  480. }
  481. /*---------------------------------------------------------------------
  482. Function: TS_AddTask
  483. Adds a new task to our list of tasks.
  484. ---------------------------------------------------------------------*/
  485. static void TS_AddTask
  486. (
  487. task *node
  488. )
  489. {
  490. LL_SortedInsertion( TaskList, node, next, prev, task, priority );
  491. }
  492. /*---------------------------------------------------------------------
  493. Function: TS_Terminate
  494. Ends processing of a specific task.
  495. ---------------------------------------------------------------------*/
  496. int TS_Terminate
  497. (
  498. task *NodeToRemove
  499. )
  500. {
  501. task *ptr;
  502. task *next;
  503. unsigned flags;
  504. flags = DisableInterrupts();
  505. ptr = TaskList->next;
  506. while( ptr != TaskList )
  507. {
  508. next = ptr->next;
  509. if ( ptr == NodeToRemove )
  510. {
  511. LL_RemoveNode( NodeToRemove, next, prev );
  512. NodeToRemove->next = NULL;
  513. NodeToRemove->prev = NULL;
  514. FreeMem( NodeToRemove );
  515. TS_SetTimerToMaxTaskRate();
  516. RestoreInterrupts( flags );
  517. return( TASK_Ok );
  518. }
  519. ptr = next;
  520. }
  521. RestoreInterrupts( flags );
  522. return( TASK_Warning );
  523. }
  524. /*---------------------------------------------------------------------
  525. Function: TS_Dispatch
  526. Begins processing of all inactive tasks.
  527. ---------------------------------------------------------------------*/
  528. void TS_Dispatch
  529. (
  530. void
  531. )
  532. {
  533. task *ptr;
  534. unsigned flags;
  535. flags = DisableInterrupts();
  536. ptr = TaskList->next;
  537. while( ptr != TaskList )
  538. {
  539. ptr->active = TRUE;
  540. ptr = ptr->next;
  541. }
  542. RestoreInterrupts( flags );
  543. }
  544. /*---------------------------------------------------------------------
  545. Function: TS_SetTaskRate
  546. Sets the rate at which the specified task is serviced.
  547. ---------------------------------------------------------------------*/
  548. void TS_SetTaskRate
  549. (
  550. task *Task,
  551. int rate
  552. )
  553. {
  554. unsigned flags;
  555. flags = DisableInterrupts();
  556. Task->rate = TS_SetTimer( rate );
  557. TS_SetTimerToMaxTaskRate();
  558. RestoreInterrupts( flags );
  559. }
  560. #ifdef LOCKMEMORY
  561. /*---------------------------------------------------------------------
  562. Function: TS_LockEnd
  563. Used for determining the length of the functions to lock in memory.
  564. ---------------------------------------------------------------------*/
  565. static void TS_LockEnd
  566. (
  567. void
  568. )
  569. {
  570. }
  571. /*---------------------------------------------------------------------
  572. Function: TS_UnlockMemory
  573. Unlocks all neccessary data.
  574. ---------------------------------------------------------------------*/
  575. void TS_UnlockMemory
  576. (
  577. void
  578. )
  579. {
  580. DPMI_UnlockMemoryRegion( TS_LockStart, TS_LockEnd );
  581. DPMI_Unlock( TaskList );
  582. DPMI_Unlock( OldInt8 );
  583. DPMI_Unlock( TaskServiceRate );
  584. DPMI_Unlock( TaskServiceCount );
  585. DPMI_Unlock( TS_Installed );
  586. #ifndef NOINTS
  587. DPMI_Unlock( TS_TimesInInterrupt );
  588. #endif
  589. #ifdef USESTACK
  590. DPMI_Unlock( StackSelector );
  591. DPMI_Unlock( StackPointer );
  592. DPMI_Unlock( oldStackSelector );
  593. DPMI_Unlock( oldStackPointer );
  594. #endif
  595. }
  596. /*---------------------------------------------------------------------
  597. Function: TS_LockMemory
  598. Locks all neccessary data.
  599. ---------------------------------------------------------------------*/
  600. int TS_LockMemory
  601. (
  602. void
  603. )
  604. {
  605. int status;
  606. status = DPMI_LockMemoryRegion( TS_LockStart, TS_LockEnd );
  607. status |= DPMI_Lock( TaskList );
  608. status |= DPMI_Lock( OldInt8 );
  609. status |= DPMI_Lock( TaskServiceRate );
  610. status |= DPMI_Lock( TaskServiceCount );
  611. status |= DPMI_Lock( TS_Installed );
  612. #ifndef NOINTS
  613. status |= DPMI_Lock( TS_TimesInInterrupt );
  614. #endif
  615. #ifdef USESTACK
  616. status |= DPMI_Lock( StackSelector );
  617. status |= DPMI_Lock( StackPointer );
  618. status |= DPMI_Lock( oldStackSelector );
  619. status |= DPMI_Lock( oldStackPointer );
  620. #endif
  621. if ( status != DPMI_Ok )
  622. {
  623. TS_UnlockMemory();
  624. return( TASK_Error );
  625. }
  626. return( TASK_Ok );
  627. }
  628. #endif
  629. /*
  630. // Converts a hex byte to an integer
  631. static int btoi
  632. (
  633. unsigned char bcd
  634. )
  635. {
  636. unsigned b;
  637. unsigned c;
  638. unsigned d;
  639. b = bcd / 16;
  640. c = bcd - b * 16;
  641. d = b * 10 + c;
  642. return( d );
  643. }
  644. static void RestoreRealTimeClock
  645. (
  646. void
  647. )
  648. {
  649. int read;
  650. int i;
  651. int hr;
  652. int min;
  653. int sec;
  654. int cent;
  655. int yr;
  656. int mo;
  657. int day;
  658. int year;
  659. union REGS inregs;
  660. // Read Real Time Clock Time.
  661. read = FALSE;
  662. inregs.h.ah = 0x02;
  663. for( i = 1; i <= 3; i++ )
  664. {
  665. int386( 0x1A, &inregs, &inregs );
  666. if ( inregs.x.cflag == 0 )
  667. {
  668. read = TRUE;
  669. }
  670. }
  671. if ( read )
  672. {
  673. //and convert BCD to integer format
  674. hr = btoi( inregs.h.ch );
  675. min = btoi( inregs.h.cl );
  676. sec = btoi( inregs.h.dh );
  677. // Read Real Time Clock Date.
  678. inregs.h.ah = 0x04;
  679. int386( 0x1A, &inregs, &inregs );
  680. if ( inregs.x.cflag == 0 )
  681. {
  682. //and convert BCD to integer format
  683. cent = btoi( inregs.h.ch );
  684. yr = btoi( inregs.h.cl );
  685. mo = btoi( inregs.h.dh );
  686. day = btoi( inregs.h.dl );
  687. year = cent * 100 + yr;
  688. // Set System Time.
  689. inregs.h.ch = hr;
  690. inregs.h.cl = min;
  691. inregs.h.dh = sec;
  692. inregs.h.dl = 0;
  693. inregs.h.ah = 0x2D;
  694. int386( 0x21, &inregs, &inregs );
  695. // Set System Date.
  696. inregs.w.cx = year;
  697. inregs.h.dh = mo;
  698. inregs.h.dl = day;
  699. inregs.h.ah = 0x2B;
  700. int386( 0x21, &inregs, &inregs );
  701. }
  702. }
  703. }
  704. */
  705. /*
  706. struct dostime_t time;
  707. struct dosdate_t date;
  708. outp(0x70,0);
  709. time.second=inp(0x71);
  710. outp(0x70,2);
  711. time.minute=inp(0x71);
  712. outp(0x70,4);
  713. time.hour=inp(0x71);
  714. outp(0x70,7);
  715. date.day=inp(0x71);
  716. outp(0x70,8);
  717. date.month=inp(0x71);
  718. outp(0x70,9);
  719. date.year=inp(0x71);
  720. time.second=(time.second&0x0f)+((time.second>>4)*10);
  721. time.minute=(time.minute&0x0f)+((time.minute>>4)*10);
  722. time.hour=(time.hour&0x0f)+((time.hour>>4)*10);
  723. date.day=(date.day&0x0f)+((date.day>>4)*10);
  724. date.month=(date.month&0x0f)+((date.month>>4)*10);
  725. date.year=(date.year&0x0f)+((date.year>>4)*10);
  726. _dos_settime(&time);
  727. _dos_setdate(&date);
  728. */