source: trunk/src/os2ahci/libc.c@ 160

Last change on this file since 160 was 160, checked in by David Azarewicz, 12 years ago

fixed trap dump kernel exit, some work on suspend/resume routines

File size: 25.9 KB
Line 
1/******************************************************************************
2 * libc.c - minimal subset of C runtime library for os2ahci
3 *
4 * Copyright (c) 2011 thi.guten Software Development
5 * Copyright (c) 2011 Mensys B.V.
6 *
7 * Authors: Christian Mueller, Markus Thielen
8 *
9 * Parts copied from/inspired by the Linux AHCI driver;
10 * those parts are (c) Linux AHCI/ATA maintainers
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 */
26
27#include "os2ahci.h"
28
29/* -------------------------- macros and constants ------------------------- */
30
31#define MSG_REPLACEMENT_STRING 1178 /* empty message with a single %; used
32 * for printing custom messages via
33 * DevHelp_Save_Message() */
34
35/* heap management constants */
36#define HEAP_SIZE 8192
37#define HEAP_UNIT 128
38#define HEAP_UNIT_CNT (HEAP_SIZE / HEAP_UNIT)
39
40/* ------------------------ typedefs and structures ------------------------ */
41
42#ifdef NOT_USED
43/* mdelay() calibration status */
44typedef enum {
45 MD_NOT_CALIBRATED, /* delay loop not calibrated */
46 MD_CALIBRATION_START, /* calibration run started */
47 MD_CALIBRATION_END, /* calibration run ended */
48 MD_CALIBRATION_DONE /* calibration complete */
49} MDCAL;
50static void _cdecl _far mdelay_timer_callback (ULONG timer_handle,
51 ULONG parm1,
52 ULONG parm2);
53static int mdelay_cal_end (void);
54#endif
55
56/* -------------------------- function prototypes -------------------------- */
57
58static void long_to_asc (long val,
59 char _far *buf,
60 int base,
61 int zero, int flen);
62
63/* ------------------------ global/static variables ------------------------ */
64
65/* debug COM port base address */
66u16 com_base = 0;
67
68static char hex_digits[] = "0123456789abcdef";
69static ULONG mem_lock;
70ULONG com_lock;
71
72/* message table for DosHelp_Save_Message() which prints the first string */
73static MSGTABLE init_msgtbl = {
74 MSG_REPLACEMENT_STRING,
75 1,
76 0
77};
78
79static struct {
80 long Baud;
81 u16 Data;
82} BaudCodes[] = {
83 115200, 0x0001,
84 57600, 0x0002,
85 38400, 0x0003,
86 19200, 0x0006,
87 9600, 0x000C,
88 4800, 24,
89 2400, 48,
90 1200, 96,
91 600, 192,
92 300, 384,
93 0, 0 /* end of list */
94};
95
96#ifdef NOT_USED
97/* delay loop calibration data */
98volatile MDCAL mdelay_cal_status = 0; /* delay loop calibration status */
99volatile u32 mdelay_loops_per_ms = 0; /* delay loop counter */
100#endif
101
102/* very small heap for dynamic memory management */
103static u8 heap_buf[HEAP_SIZE];
104static u8 heap_units[HEAP_UNIT_CNT];
105static ULONG heap_phys_addr;
106
107/* global info segment */
108volatile PGINFOSEG gis;
109
110
111/* ----------------------------- start of code ----------------------------- */
112
113/******************************************************************************
114 * Initialize libc components
115 */
116void init_libc(void)
117{
118 PSEL p;
119
120 DevHelp_CreateSpinLock(&mem_lock);
121 DevHelp_CreateSpinLock(&com_lock);
122
123 DevHelp_VirtToPhys(heap_buf, &heap_phys_addr);
124
125 /* get global info segment */
126 if (DevHelp_GetDOSVar(DHGETDOSV_SYSINFOSEG, 0, (PPVOID) &p) == 0) {
127 gis = (PGINFOSEG) ((u32) *p << 16);
128 }
129
130}
131
132/******************************************************************************
133 * Initialize COM port to 115200,n,8,1
134 *
135 * NOTE: Something is wrong with this code, or the init sequence, but we never
136 * got around to fixing it because it works fine on Virtualbox, and on
137 * physical machines we tend to have the kernel debugger running on the
138 * same port, thus KDB will set port parameters for us. This is going
139 * to be fixed eventually...
140 */
141void init_com(long BaudRate)
142{
143 int i;
144 u16 RegData;
145
146 if (com_base == 0) return; /* no com port in use */
147
148 /* Find the baud code for the given baud rate */
149 for (i = 0; BaudCodes[i].Baud; i++) if (BaudCodes[i].Baud == BaudRate) break;
150 if (BaudCodes[i].Baud == 0) i = 0; /* default to 115200 */
151 RegData = BaudCodes[i].Data;
152
153 spin_lock(com_lock);
154
155 __asm {
156 mov bx,RegData
157 mov dx,com_base ; Base address
158 cli
159 add dx,3 ; Line Control (+3)
160 mov al,10000000b ; Set baud flag
161 out dx,al ; for speed setting
162
163 ; Set Baud
164 dec dx ; High divisor address
165 dec dx ; (+1)
166 mov al,bh ; High divisor value
167 out dx,al ; set it
168 dec dx ; Low divisor address (+0)
169 mov al,bl ; Low divisor value
170 out dx,al ; set baud rate
171
172 ; Set frame
173 mov al,00000011b ; Set 8 bit, none, none
174 add dx,3 ; Line Control (+3)
175 out dx,al
176
177 inc dx
178 mov al,3
179 out dx,al ; DTR & RTS to High
180 sti
181 }
182
183 spin_unlock(com_lock);
184}
185
186/******************************************************************************
187 * Print a formatted message into a string buffer. This is very basic,
188 * supporting only strings and integers (16 and 32 bits (l), decimal (d)
189 * and hex (x)). Formatting length modifiers are only supported with a single
190 * digit -- 32-bit numbers don't need more than 9 characters -- and an
191 * optional '0' in front.
192 */
193int vsprintf(char _far *buf, const char *fmt, va_list va)
194{
195 char _far *orig = buf;
196 char _far *s;
197 int lmod;
198 int fptr;
199 int zero;
200 int flen;
201
202 for (; *fmt != '\0'; fmt++) {
203 switch (*fmt) {
204
205 case '%':
206 fmt++;
207 zero = flen = 0;
208 if (*fmt >= '0' && *fmt <= '9') {
209 /* formatting length modifiers */
210 zero = (*fmt == '0') ? 1 : 0;
211 fmt += zero;
212 if ((flen = *fmt - '0') >= 1 && flen <= 9) {
213 fmt++;
214 }
215 }
216
217 /* data type modifiers */
218 lmod = (*fmt == 'l') ? 1 : 0;
219 fptr = (*fmt == 'F') ? 1 : 0;
220 fmt += lmod + fptr;
221
222 switch (*fmt) {
223
224 case 's':
225 if (fptr) {
226 char _far *p = va_arg(va, char _far *);
227 s = (p == 0) ? "[null]" : p;
228 } else {
229 char *p = va_arg(va, char *);
230 s = (p == 0) ? "[null]" : p;
231 }
232 while ((*buf = *(s++)) != '\0')
233 buf++;
234 break;
235
236 case 'c':
237 *(buf++) = (char) va_arg(va, int);
238 break;
239
240 case 'd':
241 long_to_asc((lmod) ? va_arg(va, long)
242 : va_arg(va, int), buf, 10, zero, flen);
243 buf += strlen(buf);
244 break;
245
246 case 'x':
247 long_to_asc((lmod) ? va_arg(va, u32)
248 : va_arg(va, u16), buf, 16, zero, flen);
249 buf += strlen(buf);
250 break;
251
252 case 'p':
253 if (fptr || lmod) {
254 u16 off = va_arg(va, u16);
255 u16 seg = va_arg(va, u16);
256 long_to_asc(seg, buf, 16, 1, 4);
257 buf += strlen(buf);
258 *(buf++) = ':';
259 long_to_asc(off, buf, 16, 1, 4);
260 buf += strlen(buf);
261 } else {
262 long_to_asc(va_arg(va, u16), buf, 16, 1, 4);
263 buf += strlen(buf);
264 }
265 break;
266
267 default:
268 *(buf++) = *fmt;
269 break;
270 }
271 break;
272
273 case '\n':
274 *(buf++) = '\r';
275 *(buf++) = '\n';
276 break;
277
278 default:
279 *(buf++) = *fmt;
280 break;
281
282 }
283 }
284
285 *buf = '\0';
286 return((int) (buf - orig));
287}
288
289/*******************************************************************************
290 * Print a formatted message into a string buffer. Relies on vsprintf()
291 */
292int sprintf(char _far *buf, const char *fmt, ...)
293{
294 va_list va;
295
296 va_start(va, fmt);
297 return(vsprintf(buf, fmt, va));
298}
299
300/******************************************************************************
301 * Print messages to serial port
302 *
303 * NOTES: This function uses a 1K buffer for the resulting message. Thus,
304 * messages should never exceed 1024 bytes.
305 */
306void vprintf(int ts, const char *fmt, va_list va)
307{
308 static char buf[1024];
309 char *s;
310 int len = 0;
311
312 spin_lock(com_lock);
313
314 if (ts) {
315 /* include timestamp */
316 if (gis) {
317 len = sprintf(buf, "[%ld] ", gis->msecs);
318 } else {
319 len = sprintf(buf, "[gis=0] ");
320 }
321 }
322
323 len += vsprintf(buf + len, fmt, va);
324
325 if (com_base == 0) {
326 /* write debug message to trace buffer, not COM port */
327 trace_write(buf, len);
328 spin_unlock(com_lock);
329 return;
330 }
331
332 /* write debug message to serial port */
333 for (s = buf; *s != '\0'; s++) {
334
335 /* inp() and outp() are redefined by the DDK in an incompatible
336 * way (only words). Instead of messing around with those
337 * definitions, it's safer and easier to put the whole thing
338 * into an _asm block.
339 *
340 * The C equivalent would look like this:
341 *
342 * while (!(inp(com_base + 5) & 0x20));
343 * outp(com_base, *s);
344 */
345
346 _asm {
347 /* wait until COM transmitter is idle */
348 mov dx, com_base;
349 add dx, 5;
350 transmitter_not_idle:
351 in al, dx;
352 and al, 0x20;
353 jz transmitter_not_idle;
354
355 /* output character to be sent */
356 mov dx, com_base;
357 mov bx, s;
358 mov al, [bx];
359 out dx, al;
360 };
361 }
362
363 spin_unlock(com_lock);
364}
365
366/******************************************************************************
367 * Print messages to COM port
368 */
369void printf(const char *fmt, ...)
370{
371 va_list va;
372
373 va_start(va, fmt);
374 vprintf(1, fmt, va);
375}
376
377/******************************************************************************
378 * Print messages to COM port with no time stamp
379 */
380void printf_nts(const char *fmt, ...)
381{
382 va_list va;
383
384 va_start(va, fmt);
385 vprintf(0, fmt, va);
386}
387
388
389/******************************************************************************
390 * Print a message to the system console. This works only during device driver
391 * initialization.
392 *
393 * NOTE: This function uses a 1K buffer for the resulting message. Thus,
394 * messages should never exceed 1024 bytes...
395 */
396void cprintf(const char *fmt, ...)
397{
398 static char buf[1024];
399 va_list va;
400 size_t len;
401
402 va_start(va, fmt);
403 vsprintf(buf, fmt, va);
404
405 if (debug) {
406 /* print the same message to COM1/trace as well */
407 aprintf("%s", buf);
408 }
409
410 /* remove trailing CR/LF (DevHelp_Save_Message() will add it again) */
411 if ((len = strlen(buf)) >= 2 && buf[len-1] == '\n' && buf[len-2] == '\r') {
412 buf[len-2] = '\0';
413 }
414
415 init_msgtbl.MsgStrings[0] = buf;
416 DevHelp_Save_Message((NPBYTE) &init_msgtbl);
417}
418
419/******************************************************************************
420 * Print hex buffer to COM port.
421 */
422void phex(const void _far *p, int len, const char *fmt, ...)
423{
424 va_list va;
425 const unsigned char _far *buf = p;
426 int i;
427
428 if (!debug) {
429 return;
430 }
431
432 /* print header */
433 va_start(va, fmt);
434 vprintf(1, fmt, va);
435
436 /* print hex block */
437 while (len > 0) {
438 ntprintf("%Fp ", buf);
439
440 /* print hex block */
441 for (i = 0; i < 16; i++) {
442 if (i < len) {
443 ntprintf("%c%02x", ((i == 8) ? '-' : ' '), buf[i]);
444 } else {
445 ntprintf(" ");
446 }
447 }
448
449 /* print ASCII block */
450 ntprintf(" ");
451 for (i = 0; i < ((len > 16) ? 16 : len); i++) {
452 ntprintf("%c", (buf[i] >= 32 && buf[i] < 128) ? buf[i] : '.');
453 }
454 ntprintf("\n");
455
456 buf += 16;
457 len -= 16;
458 }
459}
460
461/******************************************************************************
462 * Return length of zero-terminated string
463 */
464size_t strlen(const char _far *s)
465{
466 int len = 0;
467
468 while (*(s++) != '\0') {
469 len++;
470 }
471 return(len);
472}
473
474/******************************************************************************
475 * Copy zero-terminated string
476 */
477char _far *strcpy(char _far *dst, const char _far *src)
478{
479 char _far *orig = dst;
480
481 while ((*(dst++) = *(src++)) != '\0');
482 return(orig);
483}
484
485/******************************************************************************
486 * Compare blocks of memory
487 */
488int memcmp(void _far *p1, void _far *p2, size_t len)
489{
490 register char _far *s1 = p1;
491 register char _far *s2 = p2;
492 int n = 0;
493
494 while (len > 0) {
495 if ((n = *(s1++) - *(s2++)) != 0) {
496 return(n);
497 }
498 len--;
499 }
500 return(0);
501}
502
503/******************************************************************************
504 * Copy block from S/G list to virtual address or vice versa.
505 */
506void sg_memcpy(SCATGATENTRY _far *sg_list, USHORT sg_cnt, ULONG sg_off,
507 void _far *buf, USHORT len, SG_MEMCPY_DIRECTION dir)
508{
509 USHORT mode_flag;
510 USHORT i;
511 USHORT l;
512 ULONG phys_addr;
513 ULONG pos = 0;
514 char _far *p;
515
516 /* walk through S/G list to find the elements involved in the operation */
517 for (i = 0; i < sg_cnt && len > 0; i++) {
518 if (pos <= sg_off && pos + sg_list[i].XferBufLen > sg_off) {
519
520 /* this S/G element intersects with the block to be copied */
521 phys_addr = sg_list[i].ppXferBuf + (sg_off - pos);
522 if ((l = sg_list[i].XferBufLen - (sg_off - pos)) > len) {
523 l = len;
524 }
525
526 if (DevHelp_PhysToVirt(phys_addr, l, (PVOID) &p, &mode_flag)) {
527 panic("sg_memcpy(): DevHelp_PhysToVirt() failed");
528 }
529 if (dir == SG_TO_BUF) {
530 memcpy(buf, p, l);
531 } else {
532 memcpy(p, buf, l);
533 }
534 sg_off += l;
535 buf = (char _far *) buf + l;
536 len -= l;
537 }
538
539 pos += sg_list[i].XferBufLen;
540 }
541}
542
543/******************************************************************************
544 * Convert a string to a long value using the specified base
545 */
546long strtol(const char _far *buf, const char _far * _far *ep, int base)
547{
548 register const char _far *s = buf;
549 long val = 0;
550 int negative = 0;
551
552 /* skip leading whitespace */
553 while (*s == ' ' || *s == '\t') {
554 s++;
555 }
556
557 /* positive or negative */
558 if (*s == '-') {
559 negative = 1;
560 s++;
561 } else if (*s == '+') {
562 s++;
563 }
564
565 /* convert string to long integer */
566 for (;; s++) {
567 int digit = (*s <= '9') ? (*s - '0') : (tolower(*s) - 'a' + 10);
568 if (digit < 0 || digit >= base) {
569 break;
570 }
571 val *= base;
572 val += digit;
573 }
574
575 if (ep != NULL) {
576 *ep = s;
577 }
578 if (negative) {
579 val = -val;
580 }
581 return(val);
582}
583
584/******************************************************************************
585 * Extremely simple and stupid implementation of malloc(). The heap is very
586 * small, only 8K at the moment, and the memory blocks are managed using a
587 * simple array of "number of heap units allocated", zero meaning this unit is
588 * available. Each heap unit is currently 128 bytes.
589 *
590 * Dynamic memory is primarily used for things like ATA identify, ATAPI
591 * sense buffers, etc. and should be freed as soon as possible, otherwise
592 * we'll quickly run out of memory.
593 */
594void *malloc(size_t len)
595{
596 u16 units = (len + HEAP_UNIT - 1) / HEAP_UNIT;
597 u16 i;
598 u16 n;
599
600 spin_lock(mem_lock);
601
602 /* find a sequence of free heap units big enough for the requested length */
603 for (i = 0; i < HEAP_UNIT_CNT; i++) {
604 if (heap_units[i] == 0) {
605 for (n = i; n < i + units && n < HEAP_UNIT_CNT; n++) {
606 if (heap_units[n] != 0) {
607 break;
608 }
609 }
610 if (n == i + units) {
611 /* found a chunk large enough; update 'heap_units[]' */
612 for (; i < n; i++) {
613 heap_units[i] = (u8) (n - i);
614 }
615 spin_unlock(mem_lock);
616 return(heap_buf + (n - units) * HEAP_UNIT);
617 }
618
619 /* keep searching... */
620 i = n;
621 } else {
622 /* skip occupied heap units */
623 i += heap_units[i] - 1;
624 }
625 }
626
627 /* out of memory */
628 spin_unlock(mem_lock);
629 dprintf("malloc(%d): out of memory\n", len);
630 return(NULL);
631}
632
633/******************************************************************************
634 * Free block of memory allocted by malloc().
635 *
636 * NOTE: This function is not reentrant, thus must be called with the driver-
637 * level spinlock held. The main reason for this design is that most
638 * functions that need dynamic memory are already holding the spinlock.
639 */
640void free(void *ptr)
641{
642 u8 *p = (u8 *) ptr;
643 u16 first_unit;
644 u16 units;
645 u16 i;
646
647 if (p < heap_buf || p >= heap_buf + sizeof(heap_buf) ||
648 (u16) (p - heap_buf) % HEAP_UNIT != 0) {
649 dprintf("free(0x%p): invalid pointer (heap_buf = 0x%p)\n",
650 (u16) p, (u16) heap_buf);
651 return;
652 }
653
654 /* clear unit allocation counters in heap_units[] */
655 spin_lock(mem_lock);
656
657 first_unit = (u16) (p - heap_buf) / HEAP_UNIT;
658 units = heap_units[first_unit];
659 for (i = first_unit; i < first_unit + units; i++) {
660 heap_units[i] = 0;
661 }
662
663 spin_unlock(mem_lock);
664}
665
666/******************************************************************************
667 * Return the physical address of a pointer inside the heap buffer. This is
668 * necessary because DevHelp_VirtToPhys() can't be called at interrupt time
669 * and we need physical addresses for heap objects when requeueing unaligned
670 * IORBs inside ahci_intr -> trigger_engine.
671 *
672 * If the pointer is not a heap pointer, this function falls back to calling
673 * DevHelp_VirtToPhys with all consequences (i.e. a trap when this is done
674 * at interrupt time).
675 */
676ULONG virt_to_phys(void _far *ptr)
677{
678 if (ptr < heap_buf || ptr > heap_buf + sizeof(heap_buf)) {
679 ULONG addr;
680
681 if (DevHelp_VirtToPhys(ptr, &addr) != 0) {
682 panic("virt_to_phys(): invalid pointer or execution mode");
683 }
684 return(addr);
685 }
686
687 return(heap_phys_addr + ((char _far *) ptr - (char _far *) heap_buf));
688}
689
690#ifdef NOT_USED
691/******************************************************************************
692 * Calibrate 'mdelay()' loop. This is done by setting up a 1 second timer
693 * with a callback that sets 'mdelay_done' to MD_CALIBRATION_END. Then it
694 * calls mdelay() with a large milliseond value as initial delay loop counter.
695 * When the timer triggers, 'mdelay()' will stop and update the delay loop
696 * counter.
697 *
698 * This function needs to be called at device driver init time. Since it uses
699 * ADD timers, it must be called with interrupts enabled. All this is not very
700 * precise (we should wait for a clock tick before starting, ...) but we don't
701 * really need precise timers.
702 */
703void mdelay_cal(void)
704{
705 ULONG timer_handle;
706
707 dprintf("calibrating delay loop... ");
708
709 mdelay_loops_per_ms = 100000;
710 mdelay_cal_status = MD_CALIBRATION_START;
711
712 ADD_StartTimerMS(&timer_handle, 1000, (PFN) mdelay_timer_callback, 0, 0);
713 mdelay(999999999);
714 ADD_CancelTimer(timer_handle);
715
716 dprintf("done (loops per ms = %ld)\n", mdelay_loops_per_ms);
717}
718
719/******************************************************************************
720 * Wait specified number of milliseconds. This is implemented using a busy
721 * loop and is only good for delays in the millisecond range but never for more
722 * than a few milliseconds and only in situations where a proper timer won't do.
723 * As a rule of thumb, don't call this function and use ADD timers, instead.
724 *
725 * NOTES:
726 *
727 * - Timers are problematic on x86 platforms because there's no reliable
728 * hardware timer on all architectures and the CPU clock speed may change
729 * while executing delay loops (AMD Cool&Quiet and Intel SpeedStep), thus
730 * calibration routines won't really be sufficient. But this usually only
731 * extends the delay and we don't really need a high precision timer. The
732 * exception are things like notebooks that are clocked slower when on
733 * battery and which got booted while on battery. Should still be OK,
734 * though, because our requirements are not that strict.
735 *
736 * - The code in this function is inefficient by design to make sure it
737 * will work with future CPUs which might otherwise be too fast for
738 * our loop counters. Part of this design is using volatile variables to
739 * force memory operations.
740 *
741 * - Before using this function, call mdelay_calibrate() to determine the
742 * number of inner loops required per millisecond.
743 */
744void mdelay(u32 millies)
745{
746 volatile u32 i;
747 volatile u32 n;
748
749 for (i = 0; i < millies; i++) {
750 for (n = 0; n < mdelay_loops_per_ms; n++) {
751 if (mdelay_cal_end()) {
752 /* this is a calibration run that just ended */
753 goto complete_calibration;
754 }
755 }
756 }
757 return;
758
759complete_calibration:
760 /* complete calibration cycle */
761 if (i < 1000) {
762 /* Initial value for delay loop was too high; interpolate results for
763 * an assumed initial delay loop divided by 1000.
764 */
765 i = i * 1000 + mdelay_loops_per_ms % 1000;
766 mdelay_loops_per_ms /= 1000;
767 }
768 mdelay_loops_per_ms = (mdelay_loops_per_ms * i) / 1000;
769 mdelay_cal_status = MD_CALIBRATION_DONE;
770}
771#endif
772
773/******************************************************************************
774 * Setup the millisecond timer. This is implemented by blocking (yielding the
775 * CPU) until the system timer value indicates we're done. This function can
776 * only be called at task time, or from a context hook.
777 *
778 * NOTE: The accuracy is limited by the OS/2 timer interrupt frequency which
779 * can lead to intervals up to 55ms (18.2 timer interrupts per second).
780 */
781void timer_init(TIMER far *pTimer, u32 Milliseconds)
782{
783 pTimer->Start = gis->msecs;
784 pTimer->End = pTimer->Start + Milliseconds;
785}
786
787/******************************************************************************
788 * Check the millisecond timer. Block if not done.
789 */
790int timer_check_and_block(TIMER far *pTimer)
791{
792 u32 current;
793
794 current = gis->msecs;
795 if (pTimer->Start <= pTimer->End) {
796 if ((current >= pTimer->End) || (current < pTimer->Start)) return 1;
797 } else {
798 if ((current >= pTimer->End) && (current < pTimer->Start)) return 1;
799 }
800 DevHelp_ProcBlock((ULONG)&timer_check_and_block, 1, WAIT_IS_INTERRUPTABLE);
801 return 0;
802}
803
804/******************************************************************************
805 * Sleep specified number of milliseonds.
806 */
807void msleep(u32 millies)
808{
809 TIMER Timer;
810
811 if (millies == 0) return;
812 timer_init(&Timer, millies);
813 while (!timer_check_and_block(&Timer));
814}
815
816/******************************************************************************
817 * Halt processing by submitting an internal error. This is a last resort and
818 * should only be called when the system state is corrupt.
819 */
820void panic(char *msg)
821{
822 DevHelp_InternalError(msg, strlen(msg));
823}
824
825/******************************************************************************
826 * Disable interrupts. The reason for using a separate function for this is
827 * that the presence of _asm statements will disable compiler optimizations.
828 * In order to support nested calls, this function will return 0 if the
829 * interrupts were already disabled or != 0, if not.
830 *
831 * NOTE: SMP systems should use spinlocks.
832 */
833int disable(void)
834{
835 int rc = 0;
836
837 _asm {
838 pushf
839 pop ax
840 and ax, 0x0200; /* "interrupts enabled" bit */
841 mov rc, ax;
842 cli
843 }
844
845 return(rc);
846}
847
848/******************************************************************************
849 * Enable interrupts. The reason for using a separate function for this is
850 * that the presence of _asm statements will disable compiler optimizations.
851 *
852 * NOTE: SMP systems should use spinlocks.
853 */
854void enable(void)
855{
856 _asm sti;
857}
858
859/******************************************************************************
860 * Convert 'long' to ASCII with the specified base
861 */
862static void long_to_asc(long val, char _far *buf, int base, int zero, int flen)
863{
864 register unsigned long abs_val;
865 char tmp[80];
866 char _far *ptmp = tmp;
867 char _far *s;
868
869 if (base > 16) {
870 sprintf(buf, "[EVAL]");
871 return;
872 }
873
874 abs_val = (unsigned long) ((val < 0 && base <= 10) ? -val : val);
875 tmp[sizeof(tmp) - 1] = '\0';
876
877 for (s = ptmp + sizeof(tmp) - 2; s > ptmp; s--) {
878 *s = hex_digits[abs_val % base];
879 flen--;
880 if ((abs_val /= base) == 0) {
881 break;
882 }
883 }
884
885 /* left-pad the resulting number with zeros or spaces up to 'flen' */
886 while (flen > 0) {
887 *(--s) = (zero) ? '0' : ' ';
888 flen--;
889 }
890
891 /* prepend minus sign if val was negative and base is decimal or less */
892 if (val < 0 && base <= 0) {
893 *(--s) = '-';
894 flen--;
895 }
896
897 strcpy(buf, s);
898}
899
900#ifdef NOT_USED
901/******************************************************************************
902 * Timer callback handler for 'mdelay_calibrate()'
903 */
904static void _cdecl _far mdelay_timer_callback(ULONG timer_handle,
905 ULONG parm1,
906 ULONG parm2)
907{
908 mdelay_cal_status = MD_CALIBRATION_END;
909}
910
911/******************************************************************************
912 * Determine whether an mdelay calibration run has just ended. This is in a
913 * function to prevent overzealous optimizers from removing the whole delay
914 * loop in mdelay().
915 */
916static int mdelay_cal_end(void)
917{
918 return(mdelay_cal_status == MD_CALIBRATION_END);
919}
920#endif
Note: See TracBrowser for help on using the repository browser.