]> git.saurik.com Git - apple/boot.git/blame_incremental - i386/libsaio/biosfn.c
boot-111.tar.gz
[apple/boot.git] / i386 / libsaio / biosfn.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25/*
26 * Copyright 1993 NeXT Computer, Inc.
27 * All rights reserved.
28 */
29
30#include "bootstruct.h"
31#include "libsaio.h"
32
33#define MAX_DRIVES 8
34
35static biosBuf_t bb;
36
37int bgetc(void)
38{
39 bb.intno = 0x16;
40 bb.eax.r.h = 0x00;
41 bios(&bb);
42 return bb.eax.rr;
43}
44
45int readKeyboardStatus(void)
46{
47 bb.intno = 0x16;
48 bb.eax.r.h = 0x01;
49 bios(&bb);
50 if (bb.flags.zf) {
51 return 0;
52 } else {
53 return bb.eax.rr;
54 }
55}
56
57int readKeyboardShiftFlags(void)
58{
59 bb.intno = 0x16;
60 bb.eax.r.h = 0x02;
61 bios(&bb);
62 return bb.eax.r.l;
63}
64
65unsigned int time18(void)
66{
67 union {
68 struct {
69 unsigned int low:16;
70 unsigned int high:16;
71 } s;
72 unsigned int i;
73 } time;
74
75 bb.intno = 0x1a;
76 bb.eax.r.h = 0x00;
77 bios(&bb);
78 time.s.low = bb.edx.rr;
79 time.s.high = bb.ecx.rr;
80 return time.i;
81}
82
83unsigned long getMemoryMap( MemoryRange * rangeArray,
84 unsigned long maxRangeCount,
85 unsigned long * conMemSizePtr,
86 unsigned long * extMemSizePtr )
87{
88 #define kMemoryMapSignature 'SMAP'
89 #define kDescriptorSizeMin 20
90
91 MemoryRange * range = rangeArray;
92 unsigned long count = 0;
93 unsigned long long conMemSize = 0;
94 unsigned long long extMemTop = 0;
95
96 // The memory pointed by the rangeArray must reside within the
97 // first megabyte.
98 //
99 // Prepare for the INT15 E820h call. Each call returns a single
100 // memory range. A continuation value is returned that must be
101 // provided on a subsequent call to fetch the next range.
102 //
103 // Certain BIOSes (Award 6.00PG) expect the upper word in EAX
104 // to be cleared on entry, otherwise only a single range will
105 // be reported.
106 //
107 // Some BIOSes will simply ignore the value of ECX on entry.
108 // Probably best to keep its value at 20 to avoid surprises.
109
110 bb.ebx.rx = 0; // Initial continuation value must be zero.
111
112 while ( count < maxRangeCount )
113 {
114 bb.intno = 0x15;
115 bb.eax.rx = 0xe820;
116 bb.ecx.rx = kDescriptorSizeMin;
117 bb.edx.rx = kMemoryMapSignature;
118 bb.edi.rr = OFFSET( (unsigned long) range );
119 bb.es = SEGMENT( (unsigned long) range );
120 bios(&bb);
121
122 // Check for errors.
123
124 if ( bb.flags.cf
125 || bb.eax.rx != kMemoryMapSignature
126 || bb.ecx.rx != kDescriptorSizeMin ) break;
127
128 // Tally up the conventional/extended memory sizes.
129
130 if ( range->type == kMemoryRangeUsable ||
131 range->type == kMemoryRangeACPI ||
132 range->type == kMemoryRangeNVS )
133 {
134 // Tally the conventional memory ranges.
135 if ( range->base + range->length <= 0xa0000 )
136 conMemSize += range->length;
137
138 // Record the top of extended memory.
139 if ( range->base >= EXTENDED_ADDR &&
140 range->base >= extMemTop )
141 extMemTop = range->base + range->length;
142 }
143
144 range++;
145 count++;
146
147 // Is this the last address range?
148
149 if ( bb.ebx.rx == 0 ) break;
150 }
151
152 if (extMemTop) extMemTop -= EXTENDED_ADDR; // convert to size
153 *conMemSizePtr = conMemSize / 1024; // size in KB
154 *extMemSizePtr = extMemTop / 1024; // size in KB
155
156 return count;
157}
158
159unsigned long getExtendedMemorySize()
160{
161 // Get extended memory size for large configurations. Not used unless
162 // the INT15, E820H call (Get System Address Map) failed.
163 //
164 // Input:
165 //
166 // AX Function Code E801h
167 //
168 // Outputs:
169 //
170 // CF Carry Flag Carry cleared indicates no error.
171 // AX Extended 1 Number of contiguous KB between 1 and 16 MB,
172 // maximum 0x3C00 = 15 MB.
173 // BX Extended 2 Number of contiguous 64 KB blocks between
174 // 16 MB and 4 GB.
175 // CX Configured 1 Number of contiguous KB between 1 and 16 MB,
176 // maximum 0x3C00 = 15 MB.
177 // DX Configured 2 Number of contiguous 64 KB blocks between
178 // 16 MB and 4 GB.
179
180 bb.intno = 0x15;
181 bb.eax.rx = 0xe801;
182 bios(&bb);
183
184 // Return the size of memory above 1MB (extended memory) in kilobytes.
185
186 if ( bb.flags.cf == 0 ) return (bb.ebx.rr * 64 + bb.eax.rr);
187
188 // Get Extended memory size. Called on last resort since the return
189 // value is limited to 16-bits (a little less than 64MB max). May
190 // not be supported by modern BIOSes.
191 //
192 // Input:
193 //
194 // AX Function Code E801h
195 //
196 // Outputs:
197 //
198 // CF Carry Flag Carry cleared indicates no error.
199 // AX Memory Count Number of contiguous KB above 1MB.
200
201 bb.intno = 0x15;
202 bb.eax.rx = 0x88;
203 bios(&bb);
204
205 // Return the size of memory above 1MB (extended memory) in kilobytes.
206
207 return bb.flags.cf ? 0 : bb.eax.rr;
208}
209
210unsigned long getConventionalMemorySize()
211{
212 bb.intno = 0x12;
213 bios(&bb);
214 return bb.eax.rr; // kilobytes
215}
216
217void video_mode(int mode)
218{
219 bb.intno = 0x10;
220 bb.eax.r.h = 0x00;
221 bb.eax.r.l = mode;
222 bios(&bb);
223}
224
225int biosread(int dev, int cyl, int head, int sec, int num)
226{
227 int i;
228
229 bb.intno = 0x13;
230 sec += 1; /* sector numbers start at 1 */
231
232 for (i=0;;) {
233 bb.ecx.r.h = cyl;
234 bb.ecx.r.l = ((cyl & 0x300) >> 2) | (sec & 0x3F);
235 bb.edx.r.h = head;
236 bb.edx.r.l = dev;
237 bb.eax.r.l = num;
238 bb.ebx.rr = OFFSET(ptov(BIOS_ADDR));
239 bb.es = SEGMENT(ptov(BIOS_ADDR));
240
241 bb.eax.r.h = 0x02;
242 bios(&bb);
243
244 if ((bb.eax.r.h == 0x00) || (i++ >= 5))
245 break;
246
247 /* reset disk subsystem and try again */
248 bb.eax.r.h = 0x00;
249 bios(&bb);
250 }
251 return bb.eax.r.h;
252}
253
254int ebiosread(int dev, long sec, int count)
255{
256 int i;
257 static struct {
258 unsigned char size;
259 unsigned char reserved;
260 unsigned char numblocks;
261 unsigned char reserved2;
262 unsigned short bufferOffset;
263 unsigned short bufferSegment;
264 unsigned long long startblock;
265 } addrpacket = {0};
266 addrpacket.size = sizeof(addrpacket);
267
268 for (i=0;;) {
269 bb.intno = 0x13;
270 bb.eax.r.h = 0x42;
271 bb.edx.r.l = dev;
272 bb.esi.rr = OFFSET((unsigned)&addrpacket);
273 bb.ds = SEGMENT((unsigned)&addrpacket);
274 addrpacket.reserved = addrpacket.reserved2 = 0;
275 addrpacket.numblocks = count;
276 addrpacket.bufferOffset = OFFSET(ptov(BIOS_ADDR));
277 addrpacket.bufferSegment = SEGMENT(ptov(BIOS_ADDR));
278 addrpacket.startblock = sec;
279 bios(&bb);
280 if ((bb.eax.r.h == 0x00) || (i++ >= 5))
281 break;
282
283 /* reset disk subsystem and try again */
284 bb.eax.r.h = 0x00;
285 bios(&bb);
286 }
287 return bb.eax.r.h;
288}
289
290void putc(int ch)
291{
292 bb.intno = 0x10;
293 bb.ebx.r.h = 0x00; /* background black */
294 bb.ebx.r.l = 0x0F; /* foreground white */
295 bb.eax.r.h = 0x0e;
296 bb.eax.r.l = ch;
297 bios(&bb);
298}
299
300void putca(int ch, int attr, int repeat)
301{
302 bb.intno = 0x10;
303 bb.ebx.r.h = 0x00; /* page number */
304 bb.ebx.r.l = attr; /* attribute */
305 bb.eax.r.h = 0x9;
306 bb.eax.r.l = ch;
307 bb.ecx.rx = repeat; /* repeat count */
308 bios(&bb);
309}
310
311/* Check to see if the passed-in drive is in El Torito no-emulation mode. */
312int is_no_emulation(int drive)
313{
314 struct packet {
315 unsigned char packet_size;
316 unsigned char media_type;
317 unsigned char drive_num;
318 unsigned char ctrlr_index;
319 unsigned long lba;
320 unsigned short device_spec;
321 unsigned short buffer_segment;
322 unsigned short load_segment;
323 unsigned short sector_count;
324 unsigned char cyl_count;
325 unsigned char sec_count;
326 unsigned char head_count;
327 unsigned char reseved;
328 };
329 static struct packet pkt;
330
331 bzero(&pkt, sizeof(pkt));
332 pkt.packet_size = 0x13;
333
334 bb.intno = 0x13;
335 bb.eax.r.h = 0x4b;
336 bb.eax.r.l = 0x01; // subfunc: get info
337 bb.edx.r.l = drive;
338 bb.esi.rr = OFFSET((unsigned)&pkt);
339 bb.ds = SEGMENT((unsigned)&pkt);
340
341 bios(&bb);
342#if DEBUG
343 printf("el_torito info drive %x\n", drive);
344
345 printf("--> cf %x, eax %x\n", bb.flags.cf, bb.eax.rr);
346
347 printf("pkt_size: %x\n", pkt.packet_size);
348 printf("media_type: %x\n", pkt.media_type);
349 printf("drive_num: %x\n", pkt.drive_num);
350 printf("device_spec: %x\n", pkt.device_spec);
351 printf("press a key->\n");getc();
352#endif
353
354 /* Some BIOSes erroneously return cf = 1 */
355 /* Just check to see if the drive number is the same. */
356 if (pkt.drive_num == drive) {
357 if ((pkt.media_type & 0x0F) == 0) {
358 /* We are in no-emulation mode. */
359 return 1;
360 }
361 }
362
363 return 0;
364}
365
366#if DEBUG
367/*
368 * BIOS drive information.
369 */
370void print_drive_info(boot_drive_info_t *dp)
371{
372 // printf("buf_size = %x\n", dp->params.buf_size);
373 printf("info_flags = %x\n", dp->params.info_flags);
374 printf(" phys_cyls = %lx\n", dp->params. phys_cyls);
375 printf(" phys_heads = %lx\n", dp->params. phys_heads);
376 printf(" phys_spt = %lx\n", dp->params. phys_spt);
377 printf("phys_sectors = %lx%lx\n", ((unsigned long *)(&dp->params.phys_sectors))[1],
378 ((unsigned long *)(&dp->params.phys_sectors))[0]);
379 printf("phys_nbps = %x\n", dp->params.phys_nbps);
380 // printf("dpte_offset = %x\n", dp->params.dpte_offset);
381 // printf("dpte_segment = %x\n", dp->params.dpte_segment);
382 // printf("key = %x\n", dp->params.key);
383 // printf("path_len = %x\n", dp->params. path_len);
384 // printf("reserved1 = %x\n", dp->params. reserved1);
385 // printf("reserved2 = %x\n", dp->params.reserved2);
386 //printf("bus_type[4] = %x\n", dp->params. bus_type[4]);
387 //printf("interface_type[8] = %x\n", dp->params. interface_type[8]);
388 //printf("interface_path[8] = %x\n", dp->params. interface_path[8]);
389 //printf("dev_path[8] = %x\n", dp->params. dev_path[8]);
390 // printf("reserved3 = %x\n", dp->params. reserved3);
391 // printf("checksum = %x\n", dp->params. checksum);
392
393 printf(" io_port_base = %x\n", dp->dpte.io_port_base);
394 printf(" control_port_base = %x\n", dp->dpte.control_port_base);
395 printf(" head_flags = %x\n", dp->dpte. head_flags);
396 printf(" vendor_info = %x\n", dp->dpte. vendor_info);
397 printf(" irq = %x\n", dp->dpte. irq);
398 // printf(" irq_unused = %x\n", dp->dpte. irq_unused);
399 printf(" block_count = %x\n", dp->dpte. block_count);
400 printf(" dma_channe = %x\n", dp->dpte. dma_channel);
401 printf(" dma_type = %x\n", dp->dpte. dma_type);
402 printf(" pio_type = %x\n", dp->dpte. pio_type);
403 printf(" pio_unused = %x\n", dp->dpte. pio_unused);
404 printf(" option_flags = %x\n", dp->dpte.option_flags);
405 // printf(" reserved = %x\n", dp->dpte.reserved);
406 printf(" revision = %x\n", dp->dpte. revision);
407 // printf(" checksum = %x\n", dp->dpte. checksum);
408}
409
410#endif
411
412int get_drive_info(int drive, struct driveInfo *dp)
413{
414 boot_drive_info_t *di = &dp->di;
415 int ret = 0;
416
417#if 0
418 if (maxhd == 0) {
419 bb.intno = 0x13;
420 bb.eax.r.h = 0x08;
421 bb.edx.r.l = 0x80;
422 bios(&bb);
423 if (bb.flags.cf == 0)
424 maxhd = 0x7f + bb.edx.r.l;
425 };
426
427 if (drive > maxhd)
428 return 0;
429#endif
430
431 bzero(dp, sizeof(struct driveInfo));
432 dp->biosdev = drive;
433
434 /* Check for El Torito no-emulation mode. */
435 dp->no_emulation = is_no_emulation(drive);
436
437 /* Check drive for EBIOS support. */
438 bb.intno = 0x13;
439 bb.eax.r.h = 0x41;
440 bb.edx.r.l = drive;
441 bb.ebx.rr = 0x55aa;
442 bios(&bb);
443 if((bb.ebx.rr == 0xaa55) && (bb.flags.cf == 0)) {
444 /* Get flags for supported operations. */
445 dp->uses_ebios = bb.ecx.r.l;
446 }
447
448 if (dp->uses_ebios & (EBIOS_ENHANCED_DRIVE_INFO | EBIOS_LOCKING_ACCESS | EBIOS_FIXED_DISK_ACCESS)) {
449 /* Get EBIOS drive info. */
450 static struct drive_params params;
451
452 params.buf_size = sizeof(params);
453 bb.intno = 0x13;
454 bb.eax.r.h = 0x48;
455 bb.edx.r.l = drive;
456 bb.esi.rr = OFFSET((unsigned)&params);
457 bb.ds = SEGMENT((unsigned)&params);
458 bios(&bb);
459 if(bb.flags.cf != 0 /* || params.phys_sectors < 2097152 */) {
460 dp->uses_ebios = 0;
461 di->params.buf_size = 1;
462 } else {
463 bcopy(&params, &di->params, sizeof(params));
464
465 if (drive >= BASE_HD_DRIVE &&
466 (dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) &&
467 di->params.buf_size >= 30 &&
468 !(di->params.dpte_offset == 0xFFFF && di->params.dpte_segment == 0xFFFF)) {
469 void *ptr = (void *)(di->params.dpte_offset + ((unsigned int)di->params.dpte_segment << 4));
470 bcopy(ptr, &di->dpte, sizeof(di->dpte));
471 }
472 }
473 }
474
475 if (di->params.phys_heads == 0 || di->params.phys_spt == 0) {
476 /* Either it's not EBIOS, or EBIOS didn't tell us. */
477 bb.intno = 0x13;
478 bb.eax.r.h = 0x08;
479 bb.edx.r.l = drive;
480 bios(&bb);
481 if (bb.flags.cf == 0 && bb.eax.r.h == 0) {
482 unsigned long cyl;
483 unsigned long sec;
484 unsigned long hds;
485
486 hds = bb.edx.r.h;
487 sec = bb.ecx.r.l & 0x3F;
488 if((dp->uses_ebios & EBIOS_ENHANCED_DRIVE_INFO) && (sec != 0)) {
489 cyl = (di->params.phys_sectors / ((hds + 1) * sec)) - 1;
490 }
491 else {
492 cyl = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
493 }
494 di->params.phys_heads = hds;
495 di->params.phys_spt = sec;
496 di->params.phys_cyls = cyl;
497 } else {
498 ret = -1;
499 }
500 }
501
502 if (dp->no_emulation) {
503 /* Some BIOSes give us erroneous EBIOS support information.
504 * Assume that if you're on a CD, then you can use
505 * EBIOS disk calls.
506 */
507 dp->uses_ebios |= EBIOS_FIXED_DISK_ACCESS;
508 }
509#if DEBUG
510 print_drive_info(di);
511 printf("uses_ebios = 0x%x\n", dp->uses_ebios);
512 printf("press a key->\n");getc();
513#endif
514
515 if (ret == 0) {
516 dp->valid = 1;
517 }
518 return ret;
519}
520
521void setCursorPosition(int x, int y, int page)
522{
523 bb.intno = 0x10;
524 bb.eax.r.h = 0x02;
525 bb.ebx.r.h = page; /* page 0 for graphics */
526 bb.edx.r.l = x;
527 bb.edx.r.h = y;
528 bios(&bb);
529}
530
531void setCursorType(int type)
532{
533 bb.intno = 0x10;
534 bb.eax.r.h = 0x01;
535 bb.ecx.rr = type;
536 bios(&bb);
537}
538
539void getCursorPositionAndType(int * x, int * y, int * type)
540{
541 bb.intno = 0x10;
542 bb.eax.r.h = 0x03;
543 bios(&bb);
544 *x = bb.edx.r.l;
545 *y = bb.edx.r.h;
546 *type = bb.ecx.rr;
547}
548
549void scollPage(int x1, int y1, int x2, int y2, int attr, int rows, int dir)
550{
551 bb.intno = 0x10;
552 bb.eax.r.h = (dir > 0) ? 0x06 : 0x07;
553 bb.eax.r.l = rows;
554 bb.ebx.r.h = attr;
555 bb.ecx.r.h = y1;
556 bb.ecx.r.l = x1;
557 bb.edx.r.h = y2;
558 bb.edx.r.l = x2;
559 bios(&bb);
560}
561
562void clearScreenRows( int y1, int y2 )
563{
564 scollPage( 0, y1, 80 - 1, y2, 0x07, y2 - y1 + 1, 1 );
565}
566
567void setActiveDisplayPage( int page )
568{
569 bb.intno = 0x10;
570 bb.eax.r.h = 5;
571 bb.eax.r.l = page;
572 bios(&bb);
573}
574
575#if DEBUG
576
577int terminateDiskEmulation()
578{
579 static char cd_spec[0x13];
580
581 bb.intno = 0x13;
582 bb.eax.r.h = 0x4b;
583 bb.eax.r.l = 0; // subfunc: terminate emulation
584 bb.esi.rr = OFFSET((unsigned)&cd_spec);
585 bb.ds = SEGMENT((unsigned)&cd_spec);
586 bios(&bb);
587 return bb.eax.r.h;
588}
589
590int readDriveParameters(int drive, struct driveParameters *dp)
591{
592 bb.intno = 0x13;
593 bb.edx.r.l = drive;
594 bb.eax.r.h = 0x08;
595 bios(&bb);
596 if (bb.eax.r.h == 0) {
597 dp->heads = bb.edx.r.h;
598 dp->sectors = bb.ecx.r.l & 0x3F;
599 dp->cylinders = bb.ecx.r.h | ((bb.ecx.r.l & 0xC0) << 2);
600 dp->totalDrives = bb.edx.r.l;
601 } else {
602 bzero(dp, sizeof(*dp));
603 }
604 return bb.eax.r.h;
605
606}
607#endif
608
609#define APM_INTNO 0x15
610#define APM_INTCODE 0x53
611
612int
613APMPresent(void)
614{
615 bb.intno = APM_INTNO;
616 bb.eax.r.h = APM_INTCODE;
617 bb.eax.r.l = 0x00;
618 bb.ebx.rr = 0x0000;
619 bios(&bb);
620 if ((bb.flags.cf == 0) &&
621 (bb.ebx.r.h == 'P') &&
622 (bb.ebx.r.l == 'M')) {
623 /* Success */
624 bootArgs->apmConfig.major_vers = bb.eax.r.h;
625 bootArgs->apmConfig.minor_vers = bb.eax.r.l;
626 bootArgs->apmConfig.flags.data = bb.ecx.rr;
627 return 1;
628 }
629 return 0;
630}
631
632int
633APMConnect32(void)
634{
635 bb.intno = APM_INTNO;
636 bb.eax.r.h = APM_INTCODE;
637 bb.eax.r.l = 0x03;
638 bb.ebx.rr = 0x0000;
639 bios(&bb);
640 if (bb.flags.cf == 0) {
641 /* Success */
642 bootArgs->apmConfig.cs32_base = (bb.eax.rr) << 4;
643 bootArgs->apmConfig.entry_offset = bb.ebx.rx;
644 bootArgs->apmConfig.cs16_base = (bb.ecx.rr) << 4;
645 bootArgs->apmConfig.ds_base = (bb.edx.rr) << 4;
646 if (bootArgs->apmConfig.major_vers >= 1 &&
647 bootArgs->apmConfig.minor_vers >= 1) {
648 bootArgs->apmConfig.cs_length = bb.esi.rr;
649 bootArgs->apmConfig.ds_length = bb.edi.rr;
650 } else {
651 bootArgs->apmConfig.cs_length =
652 bootArgs->apmConfig.ds_length = 64 * 1024;
653 }
654 bootArgs->apmConfig.connected = 1;
655 return 1;
656 }
657 return 0;
658}
659
660#ifdef EISA_SUPPORT
661BOOL
662eisa_present(
663 void
664)
665{
666 static BOOL checked;
667 static BOOL isEISA;
668
669 if (!checked) {
670 if (strncmp((char *)0xfffd9, "EISA", 4) == 0)
671 isEISA = TRUE;
672
673 checked = TRUE;
674 }
675
676 return (isEISA);
677}
678
679int
680ReadEISASlotInfo(EISA_slot_info_t *ep, int slot)
681{
682 union {
683 struct {
684 unsigned char char2h :2;
685 unsigned char char1 :5;
686 unsigned char char3 :5;
687 unsigned char char2l :3;
688 unsigned char d2 :4;
689 unsigned char d1 :4;
690 unsigned char d4 :4;
691 unsigned char d3 :4;
692 } s;
693 unsigned char data[4];
694 } u;
695 static char hex[0x10] = "0123456789ABCDEF";
696
697
698 bb.intno = 0x15;
699 bb.eax.r.h = 0xd8;
700 bb.eax.r.l = 0x00;
701 bb.ecx.r.l = slot;
702 bios(&bb);
703 if (bb.flags.cf)
704 return bb.eax.r.h;
705 ep->u_ID.d = bb.eax.r.l;
706 ep->configMajor = bb.ebx.r.h;
707 ep->configMinor = bb.ebx.r.l;
708 ep->checksum = bb.ecx.rr;
709 ep->numFunctions = bb.edx.r.h;
710 ep->u_resources.d = bb.edx.r.l;
711 u.data[0] = bb.edi.r.l;
712 u.data[1] = bb.edi.r.h;
713 u.data[2] = bb.esi.r.l;
714 u.data[3] = bb.esi.r.h;
715 ep->id[0] = u.s.char1 + ('A' - 1);
716 ep->id[1] = (u.s.char2l | (u.s.char2h << 3)) + ('A' - 1);
717 ep->id[2] = u.s.char3 + ('A' - 1);
718 ep->id[3] = hex[u.s.d1];
719 ep->id[4] = hex[u.s.d2];
720 ep->id[5] = hex[u.s.d3];
721 ep->id[6] = hex[u.s.d4];
722 ep->id[7] = 0;
723 return 0;
724}
725
726/*
727 * Note: ep must point to an address below 64k.
728 */
729
730int
731ReadEISAFuncInfo(EISA_func_info_t *ep, int slot, int function)
732{
733 bb.intno = 0x15;
734 bb.eax.r.h = 0xd8;
735 bb.eax.r.l = 0x01;
736 bb.ecx.r.l = slot;
737 bb.ecx.r.h = function;
738 bb.esi.rr = (unsigned int)ep->data;
739 bios(&bb);
740 if (bb.eax.r.h == 0) {
741 ep->slot = slot;
742 ep->function = function;
743 }
744 return bb.eax.r.h;
745}
746#endif /* EISA_SUPPORT */
747
748#define PCI_SIGNATURE 0x20494350 /* "PCI " */
749
750int
751ReadPCIBusInfo(PCI_bus_info_t *pp)
752{
753 bb.intno = 0x1a;
754 bb.eax.r.h = 0xb1;
755 bb.eax.r.l = 0x01;
756 bios(&bb);
757 if ((bb.eax.r.h == 0) && (bb.edx.rx == PCI_SIGNATURE)) {
758 pp->BIOSPresent = 1;
759 pp->u_bus.d = bb.eax.r.l;
760 pp->majorVersion = bb.ebx.r.h;
761 pp->minorVersion = bb.ebx.r.l;
762 pp->maxBusNum = bb.ecx.r.l;
763 return 0;
764 }
765 return -1;
766}
767
768void sleep(int n)
769{
770 unsigned int endtime = (time18() + 18*n);
771 while (time18() < endtime);
772}
773
774void delay(int ms)
775{
776 bb.intno = 0x15;
777 bb.eax.r.h = 0x86;
778 bb.ecx.rr = ms >> 16;
779 bb.edx.rr = ms & 0xFFFF;
780 bios(&bb);
781}