1 /* $OpenBSD: time.c,v 1.12 1998/05/30 01:53:44 mickey Exp $ */ 2 3 /* 4 * Copyright (c) 1997 Michael Shalayeff 5 * Copyright (c) 1997 Tobias Weingartner 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Tobias Weingartner. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 24 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 */ 35 36 #include <sys/time.h> 37 #include <machine/biosvar.h> 38 #include <machine/pio.h> 39 #include "libsa.h" 40 #include "biosdev.h" 41 42 #define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0) 43 44 /* 45 * Convert from bcd (packed) to int 46 */ 47 static __inline u_int8_t 48 bcdtoint(c) 49 register u_int8_t c; 50 { 51 52 return ((c & 0xf0) / 8) * 5 + (c & 0x0f); 53 } 54 55 /* 56 * Quick compute of time in seconds since the Epoch 57 */ 58 const u_short monthcount[] = { 59 0, 0, 31, 59, 90, 120, 151, 181, 60 212, 243, 273, 304, 334, 365 61 }; 62 static __inline time_t 63 compute(year, month, day, hour, min, sec) 64 int year; 65 u_int8_t month, day, hour, min, sec; 66 { 67 /* Number of days per month */ 68 register time_t tt; 69 70 /* Compute days */ 71 tt = (year - 1970) * 365 + monthcount[month] + day; 72 73 /* Compute for leap year */ 74 for(month <= 2? year--:0;year >= 1970;year--) 75 if(isleap(year)) 76 tt++; 77 78 /* Plus the time */ 79 tt = sec + 60 * (min + 60 * (tt * 24 + hour)); 80 81 return tt; 82 } 83 84 static int 85 bios_time_date(f, b) 86 int f; 87 register u_int8_t *b; 88 { 89 __asm __volatile(DOINT(0x1a) "\n\t" 90 "setc %b0\n\t" 91 "movb %%ch, 0(%2)\n\t" 92 "movb %%cl, 1(%2)\n\t" 93 "movb %%dh, 2(%2)\n\t" 94 "movb %%dl, 3(%2)\n\t" 95 : "=a" (f) 96 : "0" (f), "p" (b) : "%ecx", "%edx", "cc"); 97 if (f & 0xff) 98 return -1; 99 else { 100 b[0] = bcdtoint(b[0]); 101 b[1] = bcdtoint(b[1]); 102 b[2] = bcdtoint(b[2]); 103 b[3] = bcdtoint(b[3]); 104 return 0; 105 } 106 } 107 108 static __inline int 109 biosdate(b) 110 register u_int8_t *b; 111 { 112 return bios_time_date(4 << 8, b); 113 } 114 115 static __inline int 116 biostime(b) 117 register u_int8_t *b; 118 { 119 return bios_time_date(2 << 8, b); 120 } 121 122 /* 123 * Return time since epoch 124 */ 125 time_t 126 getsecs(void) 127 { 128 u_int8_t timebuf[4], datebuf[4]; 129 130 /* Query BIOS for time & date */ 131 if(!biostime(timebuf) && !biosdate(datebuf)) { 132 #ifdef notdef 133 int dst; 134 135 dst = timebuf[3]; 136 #endif 137 /* Convert to seconds since Epoch */ 138 return compute(datebuf[0] * 100 + datebuf[1], 139 datebuf[2], datebuf[3], 140 timebuf[0], timebuf[1], timebuf[2]); 141 } else 142 errno = EIO; 143 144 return(1); 145 } 146 147 u_int 148 sleep(i) 149 u_int i; 150 { 151 register time_t t; 152 153 /* loop for that number of seconds, polling BIOS, 154 so that it may handle interrupts */ 155 for (t = getsecs() + i; getsecs() < t; cnischar()); 156 157 return 0; 158 } 159