atapi 0.2.0

Low-level ATAPI driver in no_std environments.
Documentation
# atapi 13.09.2026

`atapi` `#![no_std]` ATAPI driver, used to bare-metal and OS dev or other drivers. It providing 
comfortable API for work with this protocol

## NOTE
you can send your offers, ideas, meaning, chatting with other devs and so on in our Discord server:
https://discord.gg/cwXhbFXm

check "is_has_device" method. For better usage implement delay function with 1us timeout

## example

Example of work ATAPI with this crate [example/sectors](./example/sectors).

```rust
fn read_pio_lba_28(&self, sectors: u8, lba: usize, mut buffer: *mut u16) -> Result<(), &'static str> {
    let count = if sectors == 0 { 256 } else { sectors as usize };

    for s in 0..count {
        let sector_lba = lba + s;

        self.set_flags(MasterOrSlave::Master, LBAOrCHS::LBA);
        self.wait_busy();
        self.set_dma_or_pio(DMAOrPIO::PIO);

        // set byte transfer limit in LBA mid and LBA high registers: 2048 bytes (0x0800)
        outb(self.io_registers.lba_mid_rw_w, 0x00);
        outb(self.io_registers.lba_high_rw_w, 0x08);

        self.prepare_scsi();
        if let Some(_) = self.wait_drq_and_busy(){
            return Err("timeout waiting for DRQ \\ \0");
        }

        // send 12-byte SCSI READ (12) packet (6 words to data port)
        let packet: [u8; 12] = [
            0xA8, // SCSI READ (12) opcode
            0x00, // flags
            ((sector_lba >> 24) & 0xFF) as u8,
            ((sector_lba >> 16) & 0xFF) as u8,
            ((sector_lba >> 8) & 0xFF) as u8,
            (sector_lba & 0xFF) as u8,
            0x00,
            0x00,
            0x00,
            1,    // 1 sector (2048 bytes)
            0x00, // reserved
            0x00, // control
        ];

        for chunk in 0..6 {
            let low = packet[chunk * 2] as u16;
            let high = (packet[chunk * 2 + 1] as u16) << 8;
            outw(self.io_registers.data_register_rw_w, low | high);
        }

        self.prepare_scsi();
        if let Some(_) = self.wait_drq_and_busy(){
            return Err("timeout waiting for DRQ \\ \0");
        }

        for _ in 0..(SECTOR_SIZE / 2) {
            unsafe {
                *buffer = inw(self.io_registers.data_register_rw_w);
                buffer = buffer.add(1);
            }
        }
    }
    Ok(())
}
```