pc_ints/
lib.rs

1#![deny(warnings)]
2#![doc(test(attr(deny(warnings))))]
3#![doc(test(attr(allow(dead_code))))]
4#![doc(test(attr(allow(unused_variables))))]
5#![allow(clippy::needless_pass_by_ref_mut)]
6
7#![no_std]
8
9#[cfg(target_os="dos")]
10use core::arch::asm;
11use core::mem::MaybeUninit;
12#[cfg(target_os="dos")]
13use core::mem::size_of;
14use core::num::NonZeroU8;
15#[cfg(target_os="dos")]
16use memoffset::offset_of;
17
18pub const DOS_ERR_FUNC_NUM_INVALID: u8 = 1;
19pub const DOS_ERR_FILE_NOT_FOUND: u8 = 2;
20pub const DOS_ERR_PATH_NOT_FOUND: u8 = 3;
21pub const DOS_ERR_TOO_MANY_OPEN_FILES: u8 = 4;
22pub const DOS_ERR_ACCESS_DENIED: u8 = 5;
23pub const DOS_ERR_INVALID_HANDLE: u8 = 6;
24pub const DOS_ERR_MCB_DESTROYED: u8 = 7;
25pub const DOS_ERR_INSUFFICIENT_MEMORY: u8 = 8;
26pub const DOS_ERR_MBA_INVALID: u8 = 9;
27pub const DOS_ERR_ENVIRONMENT_INVALID: u8 = 10;
28pub const DOS_ERR_FORMAT_INVALID: u8 = 11;
29pub const DOS_ERR_ACCESS_CODE_INVALID: u8 = 12;
30pub const DOS_ERR_DATA_INVALID: u8 = 13;
31pub const DOS_ERR_INVALID_DRIVE: u8 = 15;
32pub const DOS_ERR_ATTEMPT_RM_CUR_DIR: u8 = 16;
33pub const DOS_ERR_NOT_SAME_DEV: u8 = 17;
34pub const DOS_ERR_NO_MORE_TILES: u8 = 18;
35pub const DOS_ERR_DISK_WRITE_PROTECTED: u8 = 19;
36pub const DOS_ERR_UNKNOWN_UNIT: u8 = 20;
37pub const DOS_ERR_DRIVE_NOT_READY: u8 = 21;
38pub const DOS_ERR_UNKNOWN_CMD: u8 = 22;
39pub const DOS_ERR_DATA_ERROR: u8 = 23;
40pub const DOS_ERR_BAD_STRUCT_LEN: u8 = 24;
41pub const DOS_ERR_SEEK_ERROR: u8 = 25;
42pub const DOS_ERR_UNKNOWN_MEDIA_TYPE: u8 = 26;
43pub const DOS_ERR_SECTOR_NOT_FOUND: u8 = 27;
44pub const DOS_ERR_PRINTER_NO_PAPER: u8 = 28;
45pub const DOS_ERR_WRITE_FAULT: u8 = 29;
46pub const DOS_ERR_READ_FAULT: u8 = 30;
47pub const DOS_ERR_GENERAL_FAILURE: u8 = 31;
48pub const DOS_ERR_SHARING_VIOLATION: u8 = 32;
49pub const DOS_ERR_LOCK_VIOLATION: u8 = 33;
50pub const DOS_ERR_DISK_CHANGE_INVALID: u8 = 34;
51pub const DOS_ERR_FCB_UNAVAILABLE: u8 = 35;
52pub const DOS_ERR_SHARING_BUFFER_INVALID: u8 = 36;
53pub const DOS_ERR_CODE_PAGE_MISMATCH: u8 = 37;
54pub const DOS_ERR_OUT_OF_INPUT: u8 = 38;
55pub const DOS_ERR_INSUFFICIENT_DISK_SPACE: u8 = 39;
56pub const DOS_ERR_NET_REQUEST_NOT_SUPPORTED: u8 = 50;
57pub const DOS_ERR_NET_COMPUTER_NOT_LISTENING: u8 = 51;
58pub const DOS_ERR_NET_DUPLICATE_NAME: u8 = 52;
59pub const DOS_ERR_NET_NAME_NOT_FOUND_53: u8 = 53;
60pub const DOS_ERR_NET_BUSY: u8 = 54;
61pub const DOS_ERR_NET_DEV_NO_LONGER_EXISTS: u8 = 55;
62pub const DOS_ERR_NET_BIOS_CMD_LIMIT_EXCEEDED: u8 = 56;
63pub const DOS_ERR_NET_ADAPTER_HARDWARE_ERROR: u8 = 57;
64pub const DOS_ERR_NET_INCORRECT_RESPONSE: u8 = 58;
65pub const DOS_ERR_NET_UNEXPECTED_ERROR: u8 = 59;
66pub const DOS_ERR_NET_INCOMPATIBLE_ADAPTER: u8 = 60;
67pub const DOS_ERR_PRINT_QUEUE_FULL: u8 = 61;
68pub const DOS_ERR_QUEUE_NOT_FULL: u8 = 62;
69pub const DOS_ERR_NO_SPACE_TO_PRINT_FILE: u8 = 63;
70pub const DOS_ERR_NET_NAME_WAS_DELETED: u8 = 64;
71pub const DOS_ERR_NET_ACCESS_DENIED: u8 = 65;
72pub const DOS_ERR_NET_DEV_TYPE_INCORRECT: u8 = 66;
73pub const DOS_ERR_NET_NAME_NOT_FOUND_67: u8 = 67;
74pub const DOS_ERR_NET_NAME_LIMIT_EXCEEDED: u8 = 68;
75pub const DOS_ERR_NET_BIOS_SESSION_LIMIT_EXCEEDED: u8 = 69;
76pub const DOS_ERR_TEMPORARILY_PAUSED: u8 = 70;
77pub const DOS_ERR_NET_REQUEST_NOT_ACCEPTED: u8 = 71;
78pub const DOS_ERR_NET_REDIRECTION_PAUSED: u8 = 72;
79pub const DOS_ERR_NET_INVALID_VERSION: u8 = 73;
80pub const DOS_ERR_ACCOUNT_EXPIRED: u8 = 74;
81pub const DOS_ERR_PASSWORD_EXPIRED: u8 = 75;
82pub const DOS_ERR_LOGIN_ATTEMPTED_INVALID: u8 = 76;
83pub const DOS_ERR_NET_DISK_LIMIT_EXCEED: u8 = 77;
84pub const DOS_ERR_NET_NOT_LOGGED: u8 = 78;
85pub const DOS_ERR_FILE_EXISTS: u8 = 80;
86pub const DOS_ERR_CANNOT_MAKE_DIR: u8 = 82;
87pub const DOS_ERR_FAIL_ON_INT_24H: u8 = 83;
88pub const DOS_ERR_TOO_MANY_REDIRECTIONS: u8 = 84;
89pub const DOS_ERR_DUPLICATE_REDIRECTION: u8 = 85;
90pub const DOS_ERR_INVALID_PASSWORD: u8 = 86;
91pub const DOS_ERR_INVALID_PARAMETER: u8 = 87;
92pub const DOS_ERR_NET_WRITE_FAULT: u8 = 88;
93pub const DOS_ERR_NET_FUNC_NOT_SUPPORTED: u8 = 89;
94pub const DOS_ERR_SYS_COMPONENT_NOT_INSTALLED: u8 = 90;
95
96#[cfg(not(target_os="dos"))]
97#[allow(non_snake_case)]
98#[allow(unused_variables)]
99pub fn int_21h_ah_4Ch_exit(al_exit_code: u8) {
100    panic!("cfg(target_os=\"dos\")");
101}
102
103#[cfg(target_os="dos")]
104#[allow(non_snake_case)]
105#[inline]
106pub fn int_21h_ah_4Ch_exit(al_exit_code: u8) {
107    unsafe {
108        asm!(
109            "int 0x21",
110            in("ax") 0x4C00u16 | al_exit_code as u16,
111        );
112    }
113}
114
115#[derive(Debug, Clone)]
116pub struct DosVer {
117    pub ah_minor: u8,
118    pub al_major: u8,
119}
120
121#[cfg(not(target_os="dos"))]
122pub fn int_21h_ah_30h_dos_ver() -> DosVer {
123    panic!("cfg(target_os=\"dos\")");
124}
125
126#[cfg(target_os="dos")]
127#[inline]
128pub fn int_21h_ah_30h_dos_ver() -> DosVer {
129    let mut ax: u16;
130    unsafe {
131        asm!(
132            "int 0x21",
133            in("ax") 0x3000u16,
134            lateout("ax") ax,
135            lateout("cx") _,
136            lateout("bx") _,
137        );
138    }
139    DosVer { ah_minor: (ax >> 8) as u8, al_major: ax as u8 }
140}
141
142#[cfg(not(target_os="dos"))]
143pub fn int_21h_ah_33h_al_00h_get_ctrl_break_status() -> bool {
144    panic!("cfg(target_os=\"dos\")");
145}
146
147#[cfg(target_os="dos")]
148#[inline]
149pub fn int_21h_ah_33h_al_00h_get_ctrl_break_status() -> bool {
150    let mut dx: u16;
151    unsafe {
152        asm!(
153            "int 0x21",
154            in("ax") 0x3300u16,
155            lateout("dx") dx,
156        );
157    }
158    dx & 0xFF != 0
159}
160
161#[cfg(not(target_os="dos"))]
162#[allow(unused_variables)]
163pub fn int_21h_ah_33h_al_01h_set_ctrl_break_status(dl_ctrl_break_on: bool) {
164    panic!("cfg(target_os=\"dos\")");
165}
166
167#[cfg(target_os="dos")]
168#[inline]
169pub fn int_21h_ah_33h_al_01h_set_ctrl_break_status(dl_ctrl_break_on: bool) {
170    unsafe {
171        asm!(
172            "int 0x21",
173            in("ax") 0x3301u16,
174            in("dx") dl_ctrl_break_on as u8 as u16,
175        );
176    }
177}
178
179#[cfg(not(target_os="dos"))]
180#[allow(unused_variables)]
181pub fn int_10h_ah_02h_set_cursor_position(bh_video_page: u8, dh_row: u8, dl_column: u8) {
182    panic!("cfg(target_os=\"dos\")");
183}
184
185#[cfg(target_os="dos")]
186#[inline]
187pub fn int_10h_ah_02h_set_cursor_position(bh_video_page: u8, dh_row: u8, dl_column: u8) {
188    unsafe {
189        asm!(
190            "int 0x10",
191            in("ax") 0x0200u16,
192            in("bx") (bh_video_page as u16) << 8,
193            in("dx") ((dh_row as u16) << 8) | (dl_column as u16),
194        );
195    }
196}
197
198#[derive(Debug, Clone)]
199pub struct CodePage {
200    pub bx_active: u16,
201    pub dx_default: u16,
202}
203
204#[derive(Debug, Clone)]
205pub struct AxErr {
206    pub ax_err: u16,
207}
208
209#[cfg(target_os="dos")]
210const CF: u8 = 0x01;
211
212#[cfg(target_os="dos")]
213const ZF: u8 = 0x40;
214
215#[cfg(not(target_os="dos"))]
216pub fn int_21h_ax_6601h_code_page() -> Result<CodePage, AxErr> {
217    panic!("cfg(target_os=\"dos\")");
218}
219
220#[cfg(target_os="dos")]
221#[inline]
222pub fn int_21h_ax_6601h_code_page() -> Result<CodePage, AxErr> {
223    let mut bx_active: u16;
224    let mut dx_default: u16;
225    let mut flags: u16;
226    let mut ax_err: u16;
227    unsafe {
228        asm!(
229            "int 0x21",
230            "mov {ax_err:x}, ax",
231            "lahf",
232            ax_err = lateout(reg) ax_err,
233            in("ax") 0x6601u16,
234            lateout("ax") flags,
235            lateout("bx") bx_active,
236            lateout("dx") dx_default,
237        );
238    }
239    if ((flags >> 8) as u8) & CF == 0 {
240        Ok(CodePage { bx_active, dx_default })
241    } else {
242        Err(AxErr { ax_err })
243    }
244}
245
246#[cfg(target_os="dos")]
247#[inline]
248fn p32<T>(p: *const T) -> u32 {
249    assert!(size_of::<*const T>() == size_of::<u32>());
250    p as usize as u32
251}
252
253#[derive(Debug, Clone)]
254pub struct AlLastCh {
255    pub al_last_ch: u8,
256}
257
258#[cfg(not(target_os="dos"))]
259#[allow(unused_variables)]
260pub fn int_21h_ah_02h_out_ch(dl_ch: u8) -> AlLastCh {
261    panic!("cfg(target_os=\"dos\")");
262}
263
264#[cfg(target_os="dos")]
265#[inline]
266pub fn int_21h_ah_02h_out_ch(dl_ch: u8) -> AlLastCh {
267    let mut ax: u16;
268    unsafe {
269        asm!(
270            "int 0x21",
271            in("ax") 0x0200u16,
272            in("dx") dl_ch as u16,
273            lateout("ax") ax,
274        );
275    }
276    AlLastCh { al_last_ch: ax as u8 }
277}
278
279#[cfg(not(target_os="dos"))]
280#[allow(unused_variables)]
281pub fn int_21h_ah_09h_out_str(dx_str_24h: *const u8) {
282    panic!("cfg(target_os=\"dos\")");
283}
284
285#[cfg(target_os="dos")]
286#[inline]
287pub fn int_21h_ah_09h_out_str(dx_str_24h: *const u8) {
288    unsafe {
289        asm!(
290            "int 0x21",
291            in("ax") 0x0900u16,
292            in("edx") p32(dx_str_24h),
293            lateout("ax") _,
294        );
295    }
296}
297
298#[derive(Debug, Clone)]
299pub struct AxHandle {
300    pub ax_handle: u16,
301}
302
303#[cfg(not(target_os="dos"))]
304#[allow(non_snake_case)]
305#[allow(unused_variables)]
306pub fn int_21h_ah_3Dh_open(dx_path_z: *const u8, al_mode: u8) -> Result<AxHandle, AxErr> {
307    panic!("cfg(target_os=\"dos\")");
308}
309
310#[cfg(target_os="dos")]
311#[allow(non_snake_case)]
312#[inline]
313pub fn int_21h_ah_3Dh_open(dx_path_z: *const u8, al_mode: u8) -> Result<AxHandle, AxErr> {
314    let mut ax: u16;
315    let mut flags: u16;
316    unsafe {
317        asm!(
318            "int 0x21",
319            "mov {ax:x}, ax",
320            "lahf",
321            ax = lateout(reg) ax,
322            in("ax") 0x3d00u16 | al_mode as u16,
323            in("edx") p32(dx_path_z),
324            lateout("ax") flags,
325        );
326    }
327    if ((flags >> 8) as u8) & CF == 0 {
328        Ok(AxHandle { ax_handle: ax })
329    } else {
330        Err(AxErr { ax_err: ax })
331    }
332}
333
334#[cfg(not(target_os="dos"))]
335#[allow(non_snake_case)]
336#[allow(unused_variables)]
337pub fn int_21h_ah_3Eh_close(bx_handle: u16) -> Result<(), AxErr> {
338    panic!("cfg(target_os=\"dos\")");
339}
340
341#[cfg(target_os="dos")]
342#[allow(non_snake_case)]
343#[inline]
344pub fn int_21h_ah_3Eh_close(bx_handle: u16) -> Result<(), AxErr> {
345    let mut ax: u16;
346    let mut flags: u16;
347    unsafe {
348        asm!(
349            "int 0x21",
350            "mov {ax:x}, ax",
351            "lahf",
352            ax = lateout(reg) ax,
353            in("ax") 0x3e00u16,
354            in("bx") bx_handle,
355            lateout("ax") flags,
356        );
357    }
358    if ((flags >> 8) as u8) & CF == 0 {
359        Ok(())
360    } else {
361        Err(AxErr { ax_err: ax })
362    }
363}
364
365#[derive(Debug, Clone)]
366pub struct AxRead {
367    pub ax_read: u16,
368}
369
370#[cfg(not(target_os="dos"))]
371#[allow(non_snake_case)]
372#[allow(unused_variables)]
373pub fn int_21h_ah_3Fh_read(bx_handle: u16, dx_cx_buf: &mut [MaybeUninit<u8>]) -> Result<AxRead, AxErr> {
374    panic!("cfg(target_os=\"dos\")");
375}
376
377#[cfg(target_os="dos")]
378#[allow(non_snake_case)]
379#[inline]
380pub fn int_21h_ah_3Fh_read(bx_handle: u16, dx_cx_buf: &mut [MaybeUninit<u8>]) -> Result<AxRead, AxErr> {
381    let mut flags: u16;
382    let mut ax: u16;
383    unsafe {
384        asm!(
385            "int 0x21",
386            "mov {ax:x}, ax",
387            "lahf",
388            ax = lateout(reg) ax,
389            in("ax") 0x3F00u16,
390            in("bx") bx_handle,
391            in("ecx") u16::try_from(dx_cx_buf.len()).unwrap() as u32,
392            in("edx") p32(dx_cx_buf.as_mut_ptr()),
393            lateout("ax") flags
394        );
395    }
396    if ((flags >> 8) as u8) & CF == 0 {
397        Ok(AxRead { ax_read: ax })
398    } else {
399        Err(AxErr { ax_err: ax })
400    }
401}
402
403#[derive(Debug, Clone)]
404pub struct AxWritten {
405    pub ax_written: u16,
406}
407
408#[cfg(not(target_os="dos"))]
409#[allow(unused_variables)]
410pub fn int_21h_ah_40h_write(bx_handle: u16, dx_cx_buf: &[u8]) -> Result<AxWritten, AxErr> {
411    panic!("cfg(target_os=\"dos\")");
412}
413
414#[cfg(target_os="dos")]
415#[inline]
416pub fn int_21h_ah_40h_write(bx_handle: u16, dx_cx_buf: &[u8]) -> Result<AxWritten, AxErr> {
417    let mut flags: u16;
418    let mut ax: u16;
419    unsafe {
420        asm!(
421            "int 0x21",
422            "mov {ax:x}, ax",
423            "lahf",
424            ax = lateout(reg) ax,
425            in("ax") 0x4000u16,
426            in("bx") bx_handle,
427            in("ecx") u16::try_from(dx_cx_buf.len()).unwrap() as u32,
428            in("edx") p32(dx_cx_buf.as_ptr()),
429            lateout("ax") flags
430        );
431    }
432    if ((flags >> 8) as u8) & CF == 0 {
433        Ok(AxWritten { ax_written: ax })
434    } else {
435        Err(AxErr { ax_err: ax })
436    }
437}
438
439#[derive(Debug, Clone)]
440pub struct AxSegment {
441    pub ax_segment: u16,
442}
443
444#[derive(Debug, Clone)]
445pub struct AllocErr {
446    pub ax_err: u16,
447    pub bx_available_paragraphs: u16,
448}
449
450#[cfg(not(target_os="dos"))]
451#[allow(unused_variables)]
452pub fn int_21h_ah_48h_alloc(bx_paragraphs: u16) -> Result<AxSegment, AllocErr> {
453    panic!("cfg(target_os=\"dos\")");
454}
455
456#[cfg(target_os="dos")]
457#[inline]
458pub fn int_21h_ah_48h_alloc(bx_paragraphs: u16) -> Result<AxSegment, AllocErr> {
459    let mut ebx_paragraphs = bx_paragraphs as u32;
460    let mut ax: u16;
461    let mut flags: u16;
462    unsafe {
463        asm!(
464            "int 0x21",
465            "mov {ax:x}, ax",
466            "lahf",
467            ax = lateout(reg) ax,
468            in("ax") 0x4800u16,
469            inlateout("ebx") ebx_paragraphs => ebx_paragraphs,
470            lateout("ax") flags,
471        );
472    }
473    if ((flags >> 8) as u8) & CF == 0 {
474        Ok(AxSegment { ax_segment: ax })
475    } else {
476        Err(AllocErr { ax_err: ax, bx_available_paragraphs: ebx_paragraphs as u16 })
477    }
478}
479
480#[derive(Debug, Clone)]
481pub struct BxSegment {
482    pub bx_segment: u16,
483}
484
485#[cfg(not(target_os="dos"))]
486pub fn int_21h_ah_62h_psp_addr() -> BxSegment {
487    panic!("cfg(target_os=\"dos\")");
488}
489
490#[cfg(target_os="dos")]
491#[inline]
492pub fn int_21h_ah_62h_psp_addr() -> BxSegment {
493    let mut bx_segment: u16;
494    unsafe {
495        asm!(
496            "int 0x21",
497            in("ax") 0x6200u16,
498            lateout("bx") bx_segment,
499        );
500    }
501    BxSegment { bx_segment }
502}
503
504#[derive(Debug, Clone)]
505pub struct AlChar {
506    pub al_char: u8,
507}
508
509#[cfg(not(target_os="dos"))]
510#[allow(non_snake_case)]
511pub fn int_21h_ah_06h_dl_FFh_inkey() -> Result<Option<AlChar>, DpmiErr> {
512    panic!("cfg(target_os=\"dos\")");
513}
514
515#[cfg(target_os="dos")]
516#[repr(C)]
517struct RmRegs {
518    edi: u32,
519    esi: u32,
520    ebp: u32,
521    zero: u32,
522    ebx: u32,
523    edx: u32,
524    ecx: u32,
525    eax: u32,
526    flags: u16,
527    es: u16,
528    ds: u16,
529    fs: u16,
530    gs: u16,
531    ip: u16,
532    cs: u16,
533    sp: u16,
534    ss: u16,
535}
536
537pub struct DpmiErr(pub u16);
538
539#[cfg(target_os="dos")]
540#[allow(non_snake_case)]
541#[inline]
542pub fn int_21h_ah_06h_dl_FFh_inkey() -> Result<Option<AlChar>, DpmiErr> {
543    let mut regs = RmRegs {
544        es: 0, ds: 0, fs: 0, gs: 0, ip: 0, cs: 0, sp: 0, ss: 0,
545        edi: 0, esi: 0, ebp: 0, zero: 0, ebx: 0, ecx: 0, flags: 0,
546        edx: 0x00FF,
547        eax: 0x0600,
548    };
549    let regs = &mut regs;
550    let regs = regs as *mut _;
551    let mut regs = p32(regs);
552    let mut flags: u16;
553    let mut ax_err: u16;
554    unsafe {
555        asm!(
556            "int 0x31",
557            "mov {ax_err:x}, ax",
558            "lahf",
559            ax_err = lateout(reg) ax_err,
560            in("ax") 0x0300u16,
561            in("bx") 0x0021u16,
562            in("cx") 0x0000u16,
563            inlateout("edi") regs => regs,
564            lateout("ax") flags,
565        );
566    }
567    if ((flags >> 8) as u8) & CF == 0 {
568        let mut rm_flags: u16;
569        let mut rm_eax: u32;
570        unsafe {
571            asm!(
572                "mov {rm_flags:x}, [{regs:e} + {regs_flags_offset}]",
573                "mov {rm_eax:e}, [{regs:e} + {regs_eax_offset}]",
574                regs = in(reg) regs,
575                rm_flags = out(reg) rm_flags,
576                rm_eax = out(reg) rm_eax,
577                regs_flags_offset = const offset_of!(RmRegs, flags),
578                regs_eax_offset = const offset_of!(RmRegs, eax),
579            );
580        }
581        if rm_flags & u16::from(ZF) == 0 {
582            Ok(Some(AlChar { al_char: rm_eax as u8 }))
583        } else {
584            Ok(None)
585        }
586    } else {
587        Err(DpmiErr(ax_err))
588    }
589}
590
591#[derive(Debug, Clone)]
592pub struct CxDxAddr {
593    pub cx_segment: u16,
594    pub dx_offset: u16,
595}
596
597#[cfg(not(target_os="dos"))]
598#[allow(unused_variables)]
599pub fn int_31h_ax_0006h_segment_addr(bx_selector: u16) -> Result<CxDxAddr, AxErr> {
600    panic!("cfg(target_os=\"dos\")");
601}
602
603#[cfg(target_os="dos")]
604#[inline]
605pub fn int_31h_ax_0006h_segment_addr(bx_selector: u16) -> Result<CxDxAddr, AxErr> {
606    let mut flags: u16;
607    let mut ax_err: u16;
608    let mut cx: u16;
609    let mut dx: u16;
610    unsafe {
611        asm!(
612            "int 0x31",
613            "mov {ax_err:x}, ax",
614            "lahf",
615            ax_err = lateout(reg) ax_err,
616            in("ax") 0x0006u16,
617            in("bx") bx_selector,
618            lateout("ax") flags,
619            lateout("cx") cx,
620            lateout("dx") dx,
621        );
622    }
623    if ((flags >> 8) as u8) & CF == 0 {
624        Ok(CxDxAddr { cx_segment: cx, dx_offset: dx })
625    } else {
626        Err(AxErr { ax_err })
627    }
628}
629
630#[cfg(not(target_os="dos"))]
631#[allow(unused_variables)]
632pub fn int_31h_ax_0200h_get_rm_int(bl_vec_num: u8) -> CxDxAddr {
633    panic!("cfg(target_os=\"dos\")");
634}
635
636#[cfg(target_os="dos")]
637#[inline]
638pub fn int_31h_ax_0200h_get_rm_int(bl_vec_num: u8) -> CxDxAddr {
639    let mut cx: u16;
640    let mut dx: u16;
641    unsafe {
642        asm!(
643            "int 0x31",
644            in("ax") 0x0200u16,
645            in("bx") bl_vec_num as u16,
646            lateout("cx") cx,
647            lateout("dx") dx,
648        );
649    }
650    CxDxAddr { cx_segment: cx, dx_offset: dx }
651}
652
653#[cfg(not(target_os="dos"))]
654#[allow(unused_variables)]
655pub fn int_31h_ax_0201h_set_rm_int(bl_vec_num: u8, cx_int_handler_segment: u16, dx_int_handler_offset: u16) {
656    panic!("cfg(target_os=\"dos\")");
657}
658
659#[cfg(target_os="dos")]
660#[inline]
661pub fn int_31h_ax_0201h_set_rm_int(bl_vec_num: u8, cx_int_handler_segment: u16, dx_int_handler_offset: u16) {
662    unsafe {
663        asm!(
664            "int 0x31",
665            in("ax") 0x0201u16,
666            in("bx") bl_vec_num as u16,
667            in("cx") cx_int_handler_segment,
668            in("dx") dx_int_handler_offset,
669        );
670    }
671}
672
673#[derive(Debug, Clone)]
674pub struct RmAlloc {
675    pub ax_segment: u16,
676    pub dx_selector: u16,
677}
678
679#[cfg(not(target_os="dos"))]
680#[allow(unused_variables)]
681pub fn int_31h_ax_0100h_rm_alloc(bx_paragraphs: u16) -> Result<RmAlloc, AllocErr> {
682    panic!("cfg(target_os=\"dos\")");
683}
684
685#[cfg(target_os="dos")]
686#[inline]
687pub fn int_31h_ax_0100h_rm_alloc(mut bx_paragraphs: u16) -> Result<RmAlloc, AllocErr> {
688    let mut flags: u16;
689    let mut ax: u16;
690    let mut dx_selector: u16;
691    unsafe {
692        asm!(
693            "int 0x31",
694            "mov {ax:x}, ax",
695            "lahf",
696            ax = lateout(reg) ax,
697            in("ax") 0x0100u16,
698            inlateout("bx") bx_paragraphs => bx_paragraphs,
699            lateout("ax") flags,
700            lateout("dx") dx_selector,
701        );
702    }
703    if ((flags >> 8) as u8) & CF == 0 {
704        Ok(RmAlloc { ax_segment: ax, dx_selector })
705    } else {
706        Err(AllocErr { ax_err: ax, bx_available_paragraphs: bx_paragraphs })
707    }
708}
709
710#[cfg(not(target_os="dos"))]
711#[allow(unused_variables)]
712pub fn int_31h_ax_0101h_rm_free(dx_selector: u16) -> Result<(), AxErr> {
713    panic!("cfg(target_os=\"dos\")");
714}
715
716#[cfg(target_os="dos")]
717#[inline]
718pub fn int_31h_ax_0101h_rm_free(dx_selector: u16) -> Result<(), AxErr> {
719    let mut flags: u16;
720    let mut ax_err: u16;
721    unsafe {
722        asm!(
723            "int 0x31",
724            "mov {ax_err:x}, ax",
725            "lahf",
726            ax_err = lateout(reg) ax_err,
727            in("ax") 0x0101u16,
728            in("dx") dx_selector,
729            lateout("ax") flags,
730        );
731    }
732    if ((flags >> 8) as u8) & CF == 0 {
733        Ok(())
734    } else {
735        Err(AxErr { ax_err })
736    }
737}
738
739#[derive(Debug, Clone)]
740pub struct AlErr {
741    pub al_err: NonZeroU8,
742}
743
744#[cfg(not(target_os="dos"))]
745#[allow(unused_variables)]
746pub fn int_10h_ah_00h_set_video_mode(al_mode: u8) -> Result<(), AlErr> {
747    panic!("cfg(target_os=\"dos\")");
748}
749
750#[cfg(target_os="dos")]
751#[inline]
752pub fn int_10h_ah_00h_set_video_mode(al_mode: u8) -> Result<(), AlErr> {
753    let mut al_err: u16;
754    unsafe {
755        asm!(
756            "int 0x10",
757            in("ax") al_mode as u16,
758            lateout("ax") al_err,
759        );
760    }
761    NonZeroU8::new(al_err as u8).map(|al_err| AlErr { al_err }).map_or(Ok(()), Err)
762}
763
764#[cfg(not(target_os="dos"))]
765#[allow(unused_variables)]
766pub fn int_10h_ah_05h_set_video_active_page(al_active_page: u8) {
767    panic!("cfg(target_os=\"dos\")");
768}
769
770#[cfg(target_os="dos")]
771#[inline]
772pub fn int_10h_ah_05h_set_video_active_page(al_active_page: u8) {
773    unsafe {
774        asm!(
775            "int 0x10",
776            in("ax") 0x0500 | al_active_page as u16,
777        );
778    }
779}
780
781#[derive(Debug, Clone)]
782pub struct VideoMode {
783    pub al_mode: u8,
784    pub ah_cols: u8,
785    pub bh_active_page: u8,
786}
787
788#[cfg(not(target_os="dos"))]
789#[allow(non_snake_case)]
790#[allow(unused_variables)]
791pub fn int_10h_ah_0Fh_video_mode() -> VideoMode {
792    panic!("cfg(target_os=\"dos\")");
793}
794
795#[cfg(target_os="dos")]
796#[allow(non_snake_case)]
797#[inline]
798pub fn int_10h_ah_0Fh_video_mode() -> VideoMode {
799    let mut ax: u16;
800    let mut bx_active_page: u16;
801    unsafe {
802        asm!(
803            "int 0x10",
804            in("ax") 0x0F00u16,
805            lateout("ax") ax,
806            lateout("bx") bx_active_page,
807        );
808    }
809    VideoMode {
810        al_mode: ax as u8,
811        ah_cols: (ax >> 8) as u8,
812        bh_active_page: (bx_active_page >> 8) as u8,
813    }
814}
815
816pub struct IntHandler {
817    pub ebx_int_handler: u32,
818}
819
820#[cfg(not(target_os="dos"))]
821#[allow(unused_variables)]
822pub fn int_21h_ah_35h_get_int(al_vec_num: u8) -> IntHandler {
823    panic!("cfg(target_os=\"dos\")");
824}
825
826#[cfg(target_os="dos")]
827#[inline]
828pub fn int_21h_ah_35h_get_int(al_vec_num: u8) -> IntHandler {
829    let mut ebx_int_handler: u32;
830    unsafe {
831        asm!(
832            "int 0x21",
833            in("ax") 0x3500u16 | al_vec_num as u16,
834            lateout("ebx") ebx_int_handler,
835        );
836    }
837    IntHandler { ebx_int_handler }
838}
839
840#[cfg(not(target_os="dos"))]
841#[allow(unused_variables)]
842pub fn int_21h_ah_25h_set_int(al_vec_num: u8, edx_int_handler: u32) {
843    panic!("cfg(target_os=\"dos\")");
844}
845
846#[cfg(target_os="dos")]
847#[inline]
848pub fn int_21h_ah_25h_set_int(al_vec_num: u8, edx_int_handler: u32) {
849    unsafe {
850        asm!(
851            "int 0x21",
852            in("ax") 0x2500u16 | al_vec_num as u16,
853            in("edx") edx_int_handler,
854        );
855    }
856}