aboutsummaryrefslogtreecommitdiff
path: root/inc/dosapi.h
blob: 18dbde07678457a08e4057bfd6046db706aee527 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
/*
 * VBMouse - Interface to some DOS int 21h services
 * Copyright (C) 2022 Javier S. Pedro
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#ifndef INT21DOS_H
#define INT21DOS_H

#include <stddef.h>
#include <stdbool.h>
#include <stdint.h>
#include <dos.h>
#include "sassert.h"

#define DOS_PSP_SIZE 256

enum dos_error {
	DOS_ERROR_SUCCESS = 0,
	DOS_ERROR_INVALID_FUNCTION = 1,
	DOS_ERROR_FILE_NOT_FOUND = 2,
	DOS_ERROR_PATH_NOT_FOUND = 3,
	DOS_ERROR_TOO_MANY_OPEN_FILES = 4,
	DOS_ERROR_ACCESS_DENIED = 5,
	DOS_ERROR_INVALID_HANDLE = 6,
	DOS_ERROR_ARENA_TRASHED = 7,
	DOS_ERROR_NOT_ENOUGH_MEMORY = 8,
	DOS_ERROR_INVALID_BLOCK = 9,
	DOS_ERROR_BAD_ENVIRONMENT = 10,
	DOS_ERROR_BAD_FORMAT = 11,
	DOS_ERROR_INVALID_ACCESS = 12,
	DOS_ERROR_INVALID_DATA = 13,
	DOS_ERROR_OUT_OF_MEMORY = 14,
	DOS_ERROR_INVALID_DRIVE = 15,
	DOS_ERROR_CURRENT_DIRECTORY = 16,
	DOS_ERROR_NOT_SAME_DEVICE = 17,
	DOS_ERROR_NO_MORE_FILES = 18,
	DOS_ERROR_WRITE_PROTECT = 19,
	DOS_ERROR_BAD_UNIT = 20,
	DOS_ERROR_NOT_READY = 21,
	DOS_ERROR_BAD_COMMAND = 22,
	DOS_ERROR_CRC = 23,
	DOS_ERROR_BAD_LENGTH = 24,
	DOS_ERROR_SEEK = 25,
	DOS_ERROR_NOT_DOS_DISK = 26,
	DOS_ERROR_SECTOR_NOT_FOUND = 27,

	DOS_ERROR_GEN_FAILURE = 31,

	DOS_ERROR_HANDLE_EOF = 38,
	DOS_ERROR_HANDLE_DISK_FULL = 39,

	DOS_ERROR_FILE_EXISTS = 80,
	DOS_ERROR_CANNOT_MAKE = 82,
};

// General functions

static inline void dos_print_char(char c);
#pragma aux dos_print_char = \
	"mov ah, 0x02" \
	"int 0x21" \
	__parm [dl] \
	__modify [ah]

static inline uint8_t dos_read_char(void);
#pragma aux dos_read_char = \
	"mov ah, 0x08" \
	"int 0x21" \
	__value [al] \
	__modify [ax]

static inline void dos_print_string(const char *s);
#pragma aux dos_print_string = \
	"mov ah, 0x09" \
	"int 0x21" \
	__parm [dx] \
	__modify [ah]

static inline uint16_t dos_get_version(void);
#pragma aux dos_get_version = \
	"mov ah, 0x30" \
	"int 0x21" \
	__value [ax] \
	__modify [bx cx]

// Memory manipulation functions

typedef __segment segment_t;

enum dos_allocation_strategy {
	DOS_FIT_FIRST    = 0,
	DOS_FIT_BEST     = 1,
	DOS_FIT_LAST     = 2,

	DOS_FIT_HIGH     = 0x80,
	DOS_FIT_HIGHONLY = 0x40,
};

/** Converts bytes to paragraphs (16 bytes), rounding up. */
static inline unsigned get_paragraphs(unsigned bytes)
{
	return (bytes + 15) / 16;
}

static unsigned dos_query_allocation_strategy(void);
#pragma aux dos_query_allocation_strategy = \
	"mov ax, 0x5800" \
	"int 0x21" \
	__value [ax]

static int dos_set_allocation_strategy(unsigned strategy);
#pragma aux dos_set_allocation_strategy = \
	"clc" \
	"mov ax, 0x5801" \
	"int 0x21" \
	"jc end" \
	"mov ax, 0" \
	"end:" \
	__parm [bx] \
	__value [ax]

static bool dos_query_umb_link_state(void);
#pragma aux dos_query_umb_link_state = \
	"mov ax, 0x5802" \
	"int 0x21" \
	__value [al]

static int dos_set_umb_link_state(bool state);
#pragma aux dos_set_umb_link_state = \
	"clc" \
	"mov ax, 0x5803" \
	"int 0x21" \
	"jc end" \
	"mov ax, 0" \
	"end:" \
	__parm [bx] \
	__value [ax]

/** Allocates a new DOS segment.
 *  @returns either the allocated segment or 0 if any error. */
static __segment dos_alloc(unsigned paragraphs);
#pragma aux dos_alloc = \
	"clc" \
	"mov ah, 0x48" \
	"int 0x21" \
	"jnc end" \
	"mov ax, 0xB" \
	"end:" \
	__parm [bx] \
	__value [ax]

/** Frees DOS segment. */
static void dos_free(segment_t segment);
#pragma aux dos_free = \
	"mov ah, 0x49" \
	"int 0x21" \
	__parm [es] \
	__modify [ax]

/** Sets a given PSP as the current active process. */
static void dos_set_psp(segment_t psp);
#pragma aux dos_set_psp = \
	"mov ah, 0x50" \
	"int 0x21" \
	__parm [bx] \
	__modify [ax]

#endif // INT21DOS_H