Remove warning flags and raise WARNS where possible.
[dragonfly.git] / usr.bin / doscmd / int13.c
blob50cd9122ccbcb98a9e120cbdeeae22fe8e20c060
1 /*
2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Berkeley Software
16 * Design, Inc.
18 * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
30 * BSDI int13.c,v 2.3 1996/04/08 19:32:43 bostic Exp
32 * $FreeBSD: src/usr.bin/doscmd/int13.c,v 1.4.2.2 2002/04/25 11:04:51 tg Exp $
33 * $DragonFly: src/usr.bin/doscmd/int13.c,v 1.2 2003/06/17 04:29:26 dillon Exp $
36 #include <sys/ioctl.h>
37 #include <sys/types.h>
38 #include <sys/uio.h>
39 #include <unistd.h>
41 #include "doscmd.h"
43 #define FDCHANGED _IOR('F', 64, int)
45 #define INT13_ERR_NONE 0x00
46 #define INT13_ERR_BAD_COMMAND 0x01
47 #define INT13_ERR_BAD_ADDRESS_MARK 0x02
48 #define INT13_ERR_WRITE_PROTECT 0x03
49 #define INT13_ERR_SECTOR_ID_BAD 0x04
50 #define INT13_ERR_RESET_FAILURE 0x05
51 #define INT13_ERR_CLL_ACTIVE 0x06
52 #define INT13_ERR_ACT_FAILED 0x07
53 #define INT13_ERR_DMA_OVERRUN 0x08
54 #define INT13_ERR_DMA_BOUNDARY 0x09
55 #define INT13_ERR_BAD_TRACK_FLAG 0x0B
56 #define INT13_ERR_MEDIA_TYP_UNKNOWN 0x0C
57 #define INT13_ERR_CRC 0x10
58 #define INT13_ERR_CORRECTED 0x11
59 #define INT13_ERR_CTRLR_FAILURE 0x20
60 #define INT13_ERR_SEEK 0x40
61 #define INT13_ERR_TIME_OUT 0x80
62 #define INT13_ERR_NOT_READY 0xAA
63 #define INT13_ERR_UNDEFINED 0xBB
64 #define INT13_ERR_SENSE_OPERATION 0xFF
66 typedef struct {
67 u_char bootIndicator;
68 u_char beginHead;
69 u_char beginSector;
70 u_char beginCyl;
71 u_char systemID;
72 u_char endHead;
73 u_char endSector;
74 u_char endCyl;
75 u_long relSector;
76 u_long numSectors;
77 } PTAB;
79 struct diskinfo {
80 int type;
81 int sectors;
82 int cylinders;
83 int sides;
84 int secsize;
85 int fd;
86 char *path;
87 u_long location;
88 u_char *sector0;
89 u_long offset;
90 char *list[4]; /* Up to 4 devices allowed */
91 unsigned multi:2;
92 int read_only:1;
93 int removeable:1;
94 int changed:1; /* Set if we change format */
97 #define hd_status (*(u_char *)0x474)
98 #define fd_status (*(u_char *)0x441)
100 static inline int
101 disize(struct diskinfo *di)
103 return(di->sectors * di->cylinders * di->sides);
106 static inline int
107 cylsize(struct diskinfo *di)
109 return(di->sectors * di->sides);
112 static u_long ftable = 0xF1000; /* Floppy table */
113 static u_long htable = 0xF1020; /* Hard disk table */
115 static struct diskinfo diskinfo[26];
117 static struct diskinfo floppyinfo[] = {
118 {0, 9, 40, 1, 512, -1, NULL, 0, NULL, 0,
119 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0}, /* Probably not correct */
120 {1, 9, 40, 2, 512, -1, NULL, 0, NULL, 0,
121 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
122 {2, 9, 80, 2, 512, -1, NULL, 0, NULL, 0,
123 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
124 {3, 15, 80, 2, 512, -1, NULL, 0, NULL, 0,
125 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
126 {4, 18, 80, 2, 512, -1, NULL, 0, NULL, 0,
127 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
128 {6, 36, 80, 2, 512, -1, NULL, 0, NULL, 0,
129 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0},
130 {-1, 0, 0, 0, 0, 0, NULL, 0, NULL, 0,
131 {NULL, NULL, NULL, NULL}, 0, 0, 0, 0}
134 static struct diskinfo *
135 getdisk(int drive)
137 struct diskinfo *di;
139 if (drive >= 2 && drive < 0x80) {
140 return(0);
142 if (drive >= 0x80) {
143 drive -= 0x80;
144 drive += 2;
147 if (drive > 25 || diskinfo[drive].path == 0) {
148 return(0);
150 di = &diskinfo[drive];
151 if (di->fd < 0) {
152 if (di->removeable) {
153 di->read_only = 0;
154 if (!(di->path = di->list[di->multi]))
155 di->path = di->list[di->multi = 0];
157 if ((di->fd = open(di->path, di->read_only ? O_RDONLY
158 : O_RDWR|O_FSYNC)) < 0 &&
159 (di->read_only = 1) &&
160 (di->fd = open(di->path, O_RDONLY)) < 0) {
161 return(0);
163 di->fd = squirrel_fd(di->fd);
165 return(di);
169 disk_fd(int drive)
171 struct diskinfo *di;
173 if (drive > 1)
174 drive += 0x80 - 2;
175 di = getdisk(drive);
176 if (!di)
177 return(-1);
178 return(di->fd);
181 void
182 make_readonly(int drive)
184 if (drive < 0 || drive >= 26)
185 return;
186 diskinfo[drive].read_only = 1;
190 init_hdisk(int drive, int cyl, int head, int tracksize, char *file, char *fake_ptab)
192 struct diskinfo *di;
193 u_long table;
195 if (drive < 0) {
196 for (drive = 2; drive < 26; ++drive) {
197 if (diskinfo[drive].path == 0)
198 break;
201 if (drive < 2) {
202 fprintf(stderr, "Only floppies may be assigned to A: or B:\n");
203 return(-1);
206 if (drive >= 26) {
207 fprintf(stderr, "Too many disk drives (only 24 allowed)\n");
208 return(-1);
211 di = &diskinfo[drive];
213 if (di->path) {
214 fprintf(stderr, "Drive %c: already assigned to %s\n", drntol(drive),
215 di->path);
216 return(-1);
218 di->fd = -1;
219 di->sectors = tracksize;
220 di->cylinders = cyl;
221 di->sides = head;
222 di->sector0 = 0;
223 di->offset = 0;
225 if (fake_ptab) {
226 u_char buf[512];
227 int fd;
228 PTAB *ptab;
229 int clusters;
231 if ((fd = open(fake_ptab, 0)) < 0) {
232 perror(fake_ptab);
233 return(-1);
235 di->sector0 = malloc(512);
236 if (!di->sector0) {
237 perror("malloc in init_hdisk");
238 quit(1);
241 read(fd, di->sector0, 512);
242 close(fd);
244 ptab = (PTAB *)(di->sector0 + 0x01BE);
246 for (fd = 0; fd < 4; ++fd) {
247 if (*(u_short *)(di->sector0 + 0x1FE) == 0xAA55 &&
248 ptab[fd].numSectors == (u_long)(head * tracksize * cyl) &&
249 (ptab[fd].systemID == 1 || ptab[fd].systemID == 4 ||
250 ptab[fd].systemID == 6))
251 break;
253 if (fd < 4) {
254 if (fd)
255 memcpy(ptab, ptab + fd, sizeof(PTAB));
256 memset(ptab + 1, 0, sizeof(PTAB) * 3);
257 di->offset = ptab[0].relSector;
258 di->cylinders += di->offset / cylsize(di);
259 } else {
260 memset(ptab, 0, sizeof(PTAB) * 4);
262 ptab->beginHead = 0;
263 ptab->beginSector = 1; /* this is 1 based */
264 ptab->beginCyl = 1;
266 ptab->endHead = head - 1;
267 ptab->endSector = tracksize; /* this is 1 based */
268 ptab->endCyl = cyl & 0xff;
269 ptab->endSector |= (cyl & 0x300) >> 2;
271 ptab->relSector = head * tracksize;
272 ptab->numSectors = head * tracksize * cyl;
274 *(u_short *)(di->sector0 + 0x1FE) = 0xAA55;
276 fd = open(file, 0);
277 if (fd < 0) {
278 perror(file);
279 return(-1);
281 memset(buf, 0, 512);
282 read(fd, buf, 512);
283 close(fd);
284 if ((clusters = buf[0x0D]) == 0) {
285 if (disize(di) <= 128 * 2048)
286 clusters = 4;
287 else if (disize(di) <= 256 * 2048)
288 clusters = 8;
289 else if (disize(di) <= 8 * 1024 * 2048)
290 clusters = 16;
291 else if (disize(di) <= 16 * 1024 * 2048)
292 clusters = 32;
293 else
294 clusters = 64;
296 if ((disize(di) / clusters) <= 4096) {
297 ptab->systemID = 0x01;
298 } else {
299 ptab->systemID = 0x04;
302 di->cylinders += 1; /* Extra cylinder for partition table, etc. */
304 ptab->bootIndicator = 0x80;
306 di->type = 0xf8;
307 di->path = file;
308 di->secsize = 512;
309 di->path = strdup(file);
311 di->location = ((table & 0xf0000) << 12) | (table & 0xffff);
313 if (drive == 0) {
314 ivec[0x41] = di->location;
315 } else if (drive == 1) {
316 ivec[0x46] = di->location;
319 table = htable + (drive - 2) * 0x10;
320 *(u_short *)(table+0x00) = di->cylinders-1; /* Cylinders */
321 *(u_char *)(table+0x02) = di->sides; /* Heads */
322 *(u_short *)(table+0x03) = 0; /* 0 */
323 *(u_short *)(table+0x05) = 0xffff; /* write pre-comp */
324 *(u_char *)(table+0x07) = 0; /* ECC Burst length */
325 *(u_char *)(table+0x08) = 0; /* Control Byte */
326 *(u_char *)(table+0x09) = 0; /* standard timeout */
327 *(u_char *)(table+0x0a) = 0; /* formatting timeout */
328 *(u_char *)(table+0x0b) = 0; /* timeout for checking drive */
329 *(u_short *)(table+0x0c) = di->cylinders-1; /* landing zone */
330 *(u_char *)(table+0x0e) = di->sectors; /* sectors/track */
331 *(u_char *)(table+0x0f) = 0;
333 if ((drive - 1) >= ndisks)
334 ndisks = drive - 1;
335 return(drive);
338 static inline int
339 bps(int size)
341 switch (size) {
342 case 128: return(0);
343 case 256: return(1);
344 case 512: return(2);
345 case 1024: return(3);
346 default:
347 fprintf(stderr, "Invalid sector size: %d\n", size);
348 quit(1);
350 /* keep `gcc -Wall' happy */
351 return(0);
355 init_floppy(int drive, int type, char *file)
357 struct diskinfo *di = floppyinfo;
358 u_long table;
359 struct stat sb;
361 while (di->type >= 0 && di->type != type && disize(di)/2 != type)
362 ++di;
364 if (!di->type) {
365 fprintf(stderr, "Invalid floppy type: %d\n", type);
366 return(-1);
369 if (drive < 0) {
370 if (diskinfo[0].path == 0) {
371 drive = 0;
372 } else if (diskinfo[1].path == 0) {
373 drive = 1;
374 } else {
375 fprintf(stderr, "Too many floppy drives (only 2 allowed)\n");
376 return(-1);
379 if (drive > 1) {
380 fprintf(stderr, "Floppies must be either drive A: or B:\n");
381 return(-1);
384 if (drive >= nfloppies)
385 nfloppies = drive + 1;
387 if (diskinfo[drive].path == 0) {
388 diskinfo[drive] = *di;
391 di = &diskinfo[drive];
393 if (stat(file, &sb) < 0) {
394 fprintf(stderr, "Drive %c: Could not stat %s\n", drntol(drive), file);
395 return(-1);
398 if (drive < 2 && (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode))) {
399 if (di->path && !di->removeable) {
400 fprintf(stderr, "Drive %c: is not removeable and hence can only have one assignment\n", drntol(drive));
401 return(-1);
403 di->removeable = 1;
404 } else if (di->removeable) {
405 fprintf(stderr, "Drive %c: already assigned to %s\n", drntol(drive),
406 di->path);
407 return(-1);
410 if (di->removeable) {
411 #if 0 /*XXXXX*/
412 if (di->multi == 4) {
413 fprintf(stderr, "Drive %c: already assigned 4 devices\n",
414 drntol(drive));
415 return(-1);
417 #endif
418 di->path = di->list[di->multi++] = strdup(file);
419 } else {
420 if (di->path) {
421 fprintf(stderr, "Drive %c: already assigned to %s\n",
422 drntol(drive), di->path);
423 return(-1);
426 di->path = strdup(file);
428 di->fd = -1;
429 di->location = ((table & 0xf0000) << 12) | (table & 0xffff);
430 di->sector0 = 0;
431 di->offset = 0;
433 ivec[0x1e] = ((ftable & 0xf0000) << 12) | (ftable & 0xffff);
435 table = ftable + drive * 0x0a;
437 *(u_char *)(table+0x00) = 0xdf; /* First Specify Byte */
438 *(u_char *)(table+0x01) = 0x02; /* Second Specify Byte */
439 *(u_char *)(table+0x02) = 0x25; /* Timer ticks to wait 'til motor OFF */
440 *(u_char *)(table+0x03) = bps(di->secsize); /* Number of bytes/sector */
441 *(u_char *)(table+0x04) = di->sectors; /* Number of sectors/track */
442 *(u_char *)(table+0x05) = 0x1b; /* Gap length, in bytes */
443 *(u_char *)(table+0x06) = 0xff; /* Data length, in bytes */
444 *(u_char *)(table+0x07) = 0x6c; /* Gap length for format */
445 *(u_char *)(table+0x09) = 0xf6; /* Fill byte for formatting */
446 *(u_char *)(table+0x09) = 0x0f; /* Head settle time, in milliseconds */
447 *(u_char *)(table+0x0a) = 0x08; /* Motor startup time, in 1/8 seconds */
448 return(drive);
452 search_floppy(int i)
454 return(i < nfloppies ? diskinfo[i].type : 0);
457 #define seterror(err) { \
458 if (drive & 0x80) \
459 hd_status = err; \
460 else \
461 fd_status = err; \
462 R_AH = err; \
463 R_FLAGS |= PSL_C; \
466 static int
467 trynext(struct diskinfo *di)
469 close(di->fd);
470 di->fd = -1;
471 di->changed = 1;
472 #if 0 /*XXXXX*/
473 if (di->multi++ >= 4)
474 return(0);
475 #endif
476 if (di->list[di->multi] && (di = getdisk(di - diskinfo))) {
477 di->multi = 0;
478 return(1);
480 return(0);
483 static int
484 diread(struct diskinfo *di, regcontext_t *REGS,
485 off_t start, char *addr, int sectors)
487 off_t res;
489 int drive = di - diskinfo;
490 di->multi = -1;
492 if (drive > 1) {
493 drive -= 2;
494 drive |= 0x80;
497 again:
498 res = lseek(di->fd, start * di->secsize, 0);
500 if (res < 0 && di->removeable && trynext(di))
501 goto again;
503 if (res < 0) {
504 seterror(INT13_ERR_SEEK);
505 return(-1);
508 res = read(di->fd, addr, sectors * di->secsize);
510 if (res < 0 && di->removeable && trynext(di))
511 goto again;
513 if (di->removeable) {
514 if (res < 0) {
515 seterror(INT13_ERR_NOT_READY);
516 return(-1);
518 return(res / di->secsize);
522 * reads always work, if if they don't.
523 * Just pretend any byte not read was actually a 0
525 if (res < 0)
526 memset(addr, 0, sectors * di->secsize);
527 else if (res < sectors * di->secsize)
528 memset(addr + res, 0, sectors * di->secsize - res);
530 return(sectors);
533 static int
534 diwrite(struct diskinfo *di, regcontext_t *REGS,
535 off_t start, char *addr, int sectors)
537 off_t res;
538 int drive = di - diskinfo;
539 di->multi = -1;
541 if (drive > 1) {
542 drive -= 2;
543 drive |= 0x80;
546 again:
547 res = lseek(di->fd, start * di->secsize, 0);
549 if (res < 0 && di->removeable && trynext(di))
550 goto again;
552 if (res < 0) {
553 seterror(INT13_ERR_SEEK);
554 return(-1);
557 res = write(di->fd, addr, sectors * di->secsize);
559 if (res < 0 && di->removeable && trynext(di))
560 goto again;
562 if (di->removeable) {
563 if (res < 0) {
564 seterror(INT13_ERR_NOT_READY);
565 return(-1);
567 } else if (res < 0) {
568 seterror(INT13_ERR_WRITE_PROTECT);
569 return(-1);
571 return(res / di->secsize);
574 static void
575 int13(regcontext_t *REGS)
577 char *addr;
578 int sectors;
579 struct diskinfo *di;
580 off_t start;
581 int did;
583 int cyl;
584 int sector;
585 int side;
586 int drive;
588 reset_poll();
590 R_FLAGS &= ~PSL_C;
592 drive = R_DL;
594 if (R_AX != 0x01) {
595 if (drive & 0x80)
596 hd_status = 0;
597 else
598 fd_status = 0;
601 switch (R_AH) {
602 case 0x00: /* Reset */
603 break;
604 case 0x01: /* Read disk status */
605 if (drive & 0x80)
606 R_AH = hd_status;
607 else
608 R_AH = fd_status;
609 if (R_AH)
610 R_FLAGS |= PSL_C;
611 break;
612 case 0x02: /* Read */
613 R_AH = 0;
614 addr = (char *)MAKEPTR(R_ES, R_BX);
615 sectors = R_AL;
616 side = R_DH;
617 R_AL = 0; /* Start out with nothing read */
619 if (drive & 0x80) {
620 cyl = R_CH | ((R_CL & 0xc0) << 2);
621 sector = (R_CL & 0x3f) - 1;
622 } else {
623 sector = R_CL - 1;
624 cyl = R_CH;
627 if ((di = getdisk(drive)) == 0) {
628 debug(D_DISK, "Bad drive: %02x (%d : %d : %d)\n",
629 drive, cyl, side, sector);
630 seterror(INT13_ERR_BAD_COMMAND);
631 break;
633 start = cyl * di->sectors * di->sides +
634 side * di->sectors +
635 sector;
637 if (start >= disize(di)) {
638 debug(D_DISK, "Read past end of disk\n");
639 seterror(INT13_ERR_SEEK);
640 break;
642 if (sectors + start >= disize(di)) {
643 sectors = disize(di) - start;
646 if (di->sector0) {
647 if (start < di->offset) {
648 R_AL = sectors;
649 if (start == 0) {
650 memcpy(addr, di->sector0, di->secsize);
651 addr += di->secsize;
652 --sectors;
654 memset(addr, 0, sectors * di->secsize);
655 break;
656 } else {
657 start -= di->offset;
660 debug(D_DISK, "%02x: Read %2d sectors from %qd to %04x:%04x\n",
661 drive, sectors, start, R_ES, R_BX);
663 if ((did = diread(di, REGS, start, addr, sectors)) >= 0)
664 R_AL = did;
665 #if 0
666 callint(0x0d);
667 callint(0x76);
668 #endif
669 break;
671 case 0x03: /* Write */
672 R_AH = 0;
673 addr = (char *)MAKEPTR(R_ES, R_BX);
674 sectors = R_AL;
675 side = R_DH;
676 R_AL = 0; /* Start out with nothing written */
678 if (drive & 0x80) {
679 cyl = R_CH | ((R_CL & 0xc0) << 2);
680 sector = (R_CL & 0x3f) - 1;
681 } else {
682 sector = R_CL - 1;
683 cyl = R_CH;
686 if ((di = getdisk(drive)) == 0) {
687 debug(D_DISK, "Bad drive: %d (%d : %d : %d)\n",
688 drive, cyl, side, sector);
689 seterror(INT13_ERR_BAD_COMMAND);
690 break;
692 if (di->read_only) {
693 debug(D_DISK, "%02x: Attempt to write readonly disk\n", drive);
694 seterror(INT13_ERR_WRITE_PROTECT);
695 break;
697 start = cyl * di->sectors * di->sides +
698 side * di->sectors +
699 sector;
701 if (start >= disize(di)) {
702 debug(D_DISK, "Write past end of disk\n");
703 seterror(INT13_ERR_SEEK);
704 break;
707 if (sectors + start >= disize(di))
708 sectors = disize(di) - start;
710 if (di->sector0) {
711 if (start < di->offset) {
712 R_AL = sectors;
713 break;
714 } else {
715 start -= di->offset;
719 debug(D_DISK, "%02x: Write %2d sectors from %qd to %04x:%04x\n",
720 drive, sectors, start, R_ES, R_BX);
722 if ((did = diwrite(di, REGS, start, addr, sectors)) >= 0)
723 R_AL = did;
724 #if 0
725 callint(0x0d);
726 callint(0x76);
727 #endif
728 break;
730 case 0x04: /* Verify */
731 R_AH = 0;
732 sectors = R_AL;
733 side = R_DH;
735 if (drive & 0x80) {
736 cyl = R_CH | ((R_CL & 0xc0) << 2);
737 sector = (R_CL & 0x3f) - 1;
738 } else {
739 sector = R_CL - 1;
740 cyl = R_CH;
743 if ((di = getdisk(drive)) == 0) {
744 debug(D_DISK, "Bad drive: %d (%d : %d : %d)\n",
745 drive, cyl, side, sector);
746 seterror(INT13_ERR_BAD_COMMAND);
747 break;
749 start = cyl * di->sectors * di->sides +
750 side * di->sectors +
751 sector;
753 if (start >= disize(di)) {
754 debug(D_DISK, "Verify past end of disk\n");
755 seterror(INT13_ERR_SEEK);
756 break;
759 if (sectors + start >= disize(di))
760 sectors = disize(di) - start;
762 if (di->sector0) {
763 if (start < di->offset)
764 break;
765 else
766 start -= di->offset;
769 debug(D_DISK, "Verify %2d sectors from %qd\n", sectors, start);
770 if (lseek(di->fd, start * di->secsize, 0) < 0) {
771 debug(D_DISK, "Seek error\n");
772 seterror(INT13_ERR_SEEK);
773 break;
775 while (sectors > 0) {
776 char buf[512];
777 if (read(di->fd, buf, di->secsize) != di->secsize) {
778 debug(D_DISK, "Verify error\n");
779 seterror(0x04);
780 break;
782 --sectors;
784 #if 0
785 callint(0x0d);
786 callint(0x76);
787 #endif
788 break;
790 case 0x05: /* Format track */
791 seterror(INT13_ERR_BAD_COMMAND);
792 break;
794 case 0x08: /* Status */
795 R_AH = 0;
797 if ((di = getdisk(drive)) == 0) {
798 debug(D_DISK, "Bad drive: %d\n", drive);
799 seterror(INT13_ERR_BAD_COMMAND);
800 break;
802 R_AX = 0;
804 R_BX = di->type;
805 if ((drive & 0x80) == 0)
806 PUTVEC(R_ES, R_DI, di->location);
808 R_CL = di->sectors | ((di->cylinders >> 2) & 0xc0);
809 R_CH = di->cylinders & 0xff;
810 R_DL = (drive & 0x80) ? ndisks : nfloppies;
811 R_DH = di->sides - 1;
812 debug(D_DISK, "%02x: Status requested: sec %d cyl %d side %d drive %d\n",
813 drive, R_CL, R_CH, R_DH, R_DL);
814 #if 0
815 callint(0x0d);
816 callint(0x76);
817 #endif
818 break;
820 case 0x0c: /* Move read/write head */
821 case 0x0d: /* Reset */
822 break;
824 case 0x10: /* check for disk ready */
825 R_AH = 0; /* always open for business */
826 break;
828 case 0x15:
829 if ((di = getdisk(drive)) == 0) {
830 R_AH = 0;
831 R_FLAGS |= PSL_C;
832 break;
835 if (drive & 0x80) {
836 start = di->sectors * di->cylinders * di->sides;
837 R_CX = start >> 16;
838 R_DX = start;
839 R_AH = 3;
840 } else {
841 R_AH = 1; /* Non-changeable disk */
843 break;
845 case 0x16: /* Media change */
846 R_AH = 0;
847 if ((di = getdisk(drive)) && di->changed) {
848 di->changed = 0;
849 R_AH = 6;
851 break;
853 case 0x17: /* Determine floppy disk format */
854 seterror(INT13_ERR_BAD_COMMAND);
855 break;
857 case 0x18: /* Determine disk format */
858 if ((di = getdisk(drive)) == 0) {
859 R_AH = 0;
860 R_FLAGS |= PSL_C;
861 break;
863 /* XXX incomplete? */
864 break;
866 default:
867 unknown_int2(0x13, R_AH, REGS);
868 break;
872 void
873 disk_bios_init(void)
875 u_long vec;
877 vec = insert_softint_trampoline();
878 ivec[0x13] = vec;
879 register_callback(vec, int13, "int 13");
881 vec = insert_null_trampoline();
882 ivec[0x76] = vec;