x68000:writing_drivers
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
x68000:writing_drivers [2014/07/10 19:50] – eidis | x68000:writing_drivers [2019/08/27 20:45] (current) – external edit 127.0.0.1 | ||
---|---|---|---|
Line 2: | Line 2: | ||
The following information was kindly contributed by our forum member **Lydux**. | The following information was kindly contributed by our forum member **Lydux**. | ||
+ | |||
+ | Original thread can be found here: | ||
+ | http:// | ||
So I've decided to share with you some of my study and work. | So I've decided to share with you some of my study and work. | ||
Line 13: | Line 16: | ||
**Note :** the following contains very hard stuff ! I might be confusing sometimes, sorry in advance. Don't hesitate to ask for help if you do not understand something. Thank you. | **Note :** the following contains very hard stuff ! I might be confusing sometimes, sorry in advance. Don't hesitate to ask for help if you do not understand something. Thank you. | ||
- | |||
- | |||
- | |||
- | ---- | ||
**Terminology :** | **Terminology :** | ||
Line 24: | Line 23: | ||
* Char : 1 character = 1 byte | * Char : 1 character = 1 byte | ||
* All data types are CPU specific : M68K family. So, byte ordering is always "Big Endian" | * All data types are CPU specific : M68K family. So, byte ordering is always "Big Endian" | ||
- | |||
- | ---- | ||
====== Compilation flags, libraries and startup code ====== | ====== Compilation flags, libraries and startup code ====== | ||
Line 54: | Line 51: | ||
* __next header__ (long) : A single .SYS or .X file may contains more than one drivers, so this a pointer to the next driver header within this file. Set this member to -1 (0xFFFFFFFF) if this driver entry is the last one in the chain. | * __next header__ (long) : A single .SYS or .X file may contains more than one drivers, so this a pointer to the next driver header within this file. Set this member to -1 (0xFFFFFFFF) if this driver entry is the last one in the chain. | ||
* __attributes__ (word): This 16 bits (1 word) member are flags that give informations about the driver behavior. Valid flags are : | * __attributes__ (word): This 16 bits (1 word) member are flags that give informations about the driver behavior. Valid flags are : | ||
- | * 0x8000 : Character device driver (any driver that' | + | * 0x8000 : Character device driver (any driver that' |
* 0x4000 : IOCTL capable device. IOCTL are device specific commands that the kernel do not understand, and do not care anyway. These commands are available to userspace for a dedicated application, | * 0x4000 : IOCTL capable device. IOCTL are device specific commands that the kernel do not understand, and do not care anyway. These commands are available to userspace for a dedicated application, | ||
* 0x2000 : Remote device driver. This flag is an unique Human68k feature. When communicating to a driver having this flag setted, the kernel will deploy alternate functions that work at an higher level than block devices : filesystems. This allow the developper to use alternate way to access file on a device that the kernel do not normally understand. Think about eventual FAT32, or drive mapping over RS232/TCP. Emulators WINDRV use this flag. | * 0x2000 : Remote device driver. This flag is an unique Human68k feature. When communicating to a driver having this flag setted, the kernel will deploy alternate functions that work at an higher level than block devices : filesystems. This allow the developper to use alternate way to access file on a device that the kernel do not normally understand. Think about eventual FAT32, or drive mapping over RS232/TCP. Emulators WINDRV use this flag. | ||
Line 63: | Line 60: | ||
* 0x0002 : STDOUT device. The driver will redefine the stdout, for example : screen, serial output, printers, | * 0x0002 : STDOUT device. The driver will redefine the stdout, for example : screen, serial output, printers, | ||
* 0x0001 : STDIN device. The driver will redefine the stdin : keyboard or serial input. | * 0x0001 : STDIN device. The driver will redefine the stdin : keyboard or serial input. | ||
- | strategy | + | * __strategy |
- | | + | * __interrupt |
- | | + | * __driver |
- | Strategy and interrupt routines | + | ====== |
These 2 routines are the only ones used by the kernel to communicate with the driver. | These 2 routines are the only ones used by the kernel to communicate with the driver. | ||
+ | |||
Upon header validation, the kernel will allocate a few bytes in its own memory that' | Upon header validation, the kernel will allocate a few bytes in its own memory that' | ||
+ | |||
Next is the " | Next is the " | ||
+ | |||
This routine is responsible of analyzing the request packet, and proceed the request. | This routine is responsible of analyzing the request packet, and proceed the request. | ||
- | The Request Packet | + | ====== |
The small allocated kernel memory area will change on every kernel request. Only the first 13 bytes is a fixed structure describing the request itself, and the remaining are the request parameters. Note that the some Request Packet structure members are filled by the kernel (input), others are by the drivers as the result of the request (output). | The small allocated kernel memory area will change on every kernel request. Only the first 13 bytes is a fixed structure describing the request itself, and the remaining are the request parameters. Note that the some Request Packet structure members are filled by the kernel (input), others are by the drivers as the result of the request (output). | ||
+ | |||
Request packet structure header (fixed first 13 bytes) : | Request packet structure header (fixed first 13 bytes) : | ||
- | Request length | + | * __Request length__ |
- | | + | * __Requested unit__ |
- | | + | * __Request |
- | | + | * __Result status__ |
- | | + | * __Reserved |
- | Command execution result flags : | + | **Command execution result flags :** |
- | This list contains all acceptable values to fill the result status flags in the request packet header. | + | |
- | S_**** flags will display (or hide) the " | + | This list contains all acceptable values to fill the result status flags in the request packet header. S_**** flags will display (or hide) the " |
" | " | ||
- | | + | * 0x1000 - S_ABORT : " |
- | 0x2000 - S_RETRY : Allow to " | + | |
- | 0x4000 - S_IGNORE : The failed request can be safelly " | + | |
- | 0x0000 - E_OK : No error | + | |
- | 0x0001 - E_UNIT : The unit is unknown | + | |
- | 0x0002 - E_NOTRDY : Unit isn't ready | + | |
- | 0x0003 - E_CMD : Unknow command code | + | |
- | 0x0004 - E_CRC : CRC error | + | |
- | 0x0005 - E_LENGTH : Bad length | + | |
- | 0x0006 - E_SEEK : Seek Error | + | |
- | 0x0007 - E_MEDIA : Unknown Media | + | |
- | 0x0008 - E_NOTFND : Sector Not Found | + | |
- | 0x0009 - E_PAPER : No Paper | + | |
- | 0x000A - E_WRITE : Write Fault | + | |
- | 0x000B - E_READ : Read Fault | + | |
- | 0x000C - E_FAILURE : General Failure | + | |
- | 0x000D - E_WRPRT : Write Protect | + | |
- | 0x000E - E_DISK : Disk Change | + | |
+ | |||
+ | ====== Generic command codes and parameters ====== | ||
+ | |||
+ | Each possible request command code in the request packet header have their own set of parameters. Again some are filled by the kernel, and others by the driver. | ||
+ | |||
+ | Note that some request command code are available only for character device drivers, some only for block device drivers and some on both. Remote device drivers have their own set of command code. | ||
+ | Command parameters structure always start at position 14 within the request packet. | ||
+ | |||
+ | ===== 0x00 - Initialize ===== | ||
+ | |||
+ | **Command ID :** 0x00 (C_INIT) | ||
+ | |||
+ | **Availability :** Block/ | ||
+ | |||
+ | **Description :** | ||
+ | |||
+ | This is the initialize command and is called only once after driver loading. On initialize, the driver must perform eventual device detection and initialization, | ||
+ | |||
+ | **Input parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 18 | Long |Pointer to a null terminated string containing arguments passed via CONFIG.SYS | ||
+ | | 22 | Byte |Block device driver only. Not sure of the meaning, but this probably contains the drive number the kernel want to initialize. | ||
+ | |||
+ | |||
+ | **Output parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 13 | Byte |Block device driver only. The amount of " | ||
+ | | 14 | Long |Pointer to the end of the used memory space. This memory space include every segment sizes used by the driver : TEXT, DATA, BSS, as well as eventual HEAP. A very important parameter ! Any wrong value written here will crash the kernel. Normally, my toolchain provides a symbol usable for this parameter : " | ||
+ | | 18 | Long |Block device driver only. Pointer to an array of BPB (Bios Parameter Block). Basically, a BPB describes the FAT volume on the physical disk, so determine the size of a partition or media. For more information about BPB, see wikipedia : http:// | ||
+ | |||
+ | ===== 0x01 - Media Check ===== | ||
+ | |||
+ | **Command ID :** 0x01 (C_MEDIACHK) | ||
+ | |||
+ | **Availability :** Block | ||
+ | |||
+ | **Description :** Before performing IO operations on a block device, the kernel will process this command code to ensure the target media is still available and ready. | ||
+ | |||
+ | **Input parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 13 | Byte |Last known media type ID. See standard media type list bellow. | ||
+ | |||
+ | |||
+ | **Output parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 14 | Byte |Media status. Possible values are : | | ||
+ | | | -1 |M_CHANGED : Media was changed | ||
+ | | | 0 |M_DONT_KNOW : Media state unknown | ||
+ | | | 1 |M_NOT_CHANGED : Media still in and ready | | ||
+ | |||
+ | **Human68K standard media type list :** | ||
+ | |||
+ | Note : this list isn't exhaustive ! A driver can provide its own set. So, a program or driver should never rely on these values to determine the media type. | ||
+ | |||
+ | I will not explain them, names pretty much speak for themselves. | ||
+ | |||
+ | * 0xE0 - MD_2DD_10 | ||
+ | * 0xE5 - MD_1D_9 | ||
+ | * 0xE6 - MD_2D_9 | ||
+ | * 0xE7 - MD_1D_8 | ||
+ | * 0xE8 - MD_2D_8 | ||
+ | * 0xEA - MD_2HT | ||
+ | * 0xEB - MD_2HS | ||
+ | * 0xEC - MD_2HDE | ||
+ | * 0xEE - MD_1DD_9 | ||
+ | * 0xEF - MD_1DD_8 | ||
+ | * 0xF4 - MD_DAT | ||
+ | * 0xF5 - MD_CDROM | ||
+ | * 0xF6 - MD_MO | ||
+ | * 0xF7 - MD_SCSIHD | ||
+ | * 0xF8 - MD_SASIHD | ||
+ | * 0xF9 - MD_RAMDISK | ||
+ | * 0xFA - MD_2HQ | ||
+ | * 0xFB - MD_2DD_8 | ||
+ | * 0xFC - MD_2DD_9 | ||
+ | * 0xFD - MD_2HC | ||
+ | * 0xFE - MD_2HD | ||
+ | |||
+ | |||
+ | ===== 0x02 - Build BPB ===== | ||
+ | |||
+ | |||
+ | **Command ID :** 0x02 (C_BLDBPB) | ||
+ | |||
+ | **Availability :** Block | ||
+ | |||
+ | **Description :** This command is proceed when a media have previously been reported as " | ||
+ | |||
+ | **Input parameters :** none | ||
+ | |||
+ | **Output parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 18 | Long | Pointer to the requested unit BPB | | ||
+ | |||
+ | |||
+ | ===== 0x03 - IOCTL input ===== | ||
+ | |||
+ | **Command ID :** 0x03 (C_IOCTLIN) | ||
+ | |||
+ | **Availability :** Block/ | ||
+ | |||
+ | **Description :** Request the driver to read raw arbitrary datas from the specified unit. This request is initiated by an userspace application (IOCTL). | ||
+ | |||
+ | **Input parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 14 | Long |Pointer to a buffer that' | ||
+ | | 18 | Long |Buffer size | | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | ===== 0x04 - Input (read) ===== | ||
+ | |||
+ | **Command ID :** 0x04 (C_INPUT) | ||
+ | |||
+ | **Availability :** Block/ | ||
+ | |||
+ | **Description :** Request the driver to read data from the specified unit. This request is initiated by the kernel. | ||
+ | |||
+ | **Input parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 13 | Byte |Block device driver only. Media type. | | ||
+ | | 14 | Long |Pointer to a buffer that' | ||
+ | | 18 | Long |Block device driver : number of sector to read. A sector length is normally specified by the BPB. | | ||
+ | | | |Character device driver : Buffer size. | | ||
+ | | 22 | Long |Block device driver only : logical start sector to read from. | | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | Note for block device driver : as the kernel is responsible for handling the FAT, you just have to seek to the specified start sector location and read the wanted amount of data from there according to the requested amount of sectors and the BPB. However, the driver is still responsible of the logical to physical partition translation ! So, seek correctly. | ||
+ | |||
+ | ===== 0x05 - Read no wait ===== | ||
+ | |||
+ | **Command ID :** 0x05 (C_NDREAD) | ||
+ | |||
+ | **Availability :** Character | ||
+ | |||
+ | **Description :** To check furthermore. A strange command code that allow a driver to send back a device prereaded byte. Maybe dedicated command to some simple interrupt driven device. | ||
+ | |||
+ | **Input parameters :** none | ||
+ | |||
+ | **Output parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 13 | Byte |Prereaded byte | | ||
+ | |||
+ | ===== 0x05 - Drive control/ | ||
+ | |||
+ | **Command ID :** 0x05 (C_DRVCTL) | ||
+ | |||
+ | **Availability :** Block | ||
+ | |||
+ | **Description :** //To check furthermore.// | ||
+ | |||
+ | ===== 0x06 - Input status ===== | ||
+ | |||
+ | **Command ID :** 0x06 (C_ISTAT) | ||
+ | |||
+ | **Availability :** Character | ||
+ | |||
+ | **Description :** Kernel perform this command before the INPUT one to check if reading on the specified unit is actually possible or not. There is no parameter. Just fill the result flags in the request packet header accordingly. | ||
+ | |||
+ | **Input parameters :** none | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | ===== 0x07 - Input flush ===== | ||
+ | |||
+ | **Command ID :** 0x07 (C_IFLUSH) | ||
+ | |||
+ | **Availability :** Character | ||
+ | |||
+ | **Description :** Request the driver to flush the specified unit input buffer. There is no parameter. Just fill the result flags in the request packet header accordingly. | ||
+ | |||
+ | **Input parameters :** none | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | ===== 0x08 - Output (write) ===== | ||
+ | |||
+ | **Command ID :** 0x08 (C_OUTPUT) | ||
+ | |||
+ | **Availability :** Block/ | ||
+ | |||
+ | **Description :** Request the driver to write data to a specified unit. This request is initiated by the kernel. | ||
+ | |||
+ | **Input parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 14 | Long |Pointer to a buffer that contains data to write to the unit.| | ||
+ | | 18 | Long |Block device driver : number of sector to write. A sector length is normally specified by the BPB. | | ||
+ | | | |Character device driver : Buffer size. | | ||
+ | | 22 | Long |Block device driver only : logical start sector to write to. | | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | Note for block device driver : as the kernel is responsible for handling the FAT, you just have to seek to the specified start sector location and read the wanted amount of data from there according to the requested amount of sectors and the BPB. However, the driver is still responsible of the logical to physical partition translation ! So, seek correctly. | ||
+ | |||
+ | ===== 0x09 - Output with verify ===== | ||
+ | |||
+ | **Command ID :** 0x09 (C_OUTVFY) | ||
+ | |||
+ | **Availability :** Block/ | ||
+ | |||
+ | **Description :** Same as "0x08 - Output (write)", | ||
+ | |||
+ | **Input parameters :** same as the "0x08 - Output (write)" | ||
+ | |||
+ | ===== 0x0A - Output status ===== | ||
+ | |||
+ | **Command ID :** 0x0A (C_OSTAT) | ||
+ | |||
+ | **Availability :** Character | ||
+ | |||
+ | **Description :** Kernel perform this command before the OUTPUT one to check if writing to the specified unit is actually possible or not. There is no parameter. Just fill the result flags in the request packet header accordingly. | ||
+ | |||
+ | **Input parameters :** none | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | ===== 0x0B - Output flush ===== | ||
+ | |||
+ | **Command ID :** 0x0B (C_OFLUSH) | ||
+ | |||
+ | **Availability :** Character | ||
+ | |||
+ | **Description :** Request the driver to flush the specified unit output buffer. There is no parameter. Just fill the result flags in the request packet header accordingly. | ||
+ | |||
+ | **Input parameters :** none | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | ===== 0x0C - IOCTL out ===== | ||
+ | |||
+ | **Command ID :** 0x0C (C_IOCTLOUT) | ||
+ | |||
+ | **Availability :** Block/ | ||
+ | |||
+ | **Description :** Request the driver to write raw arbitrary datas to the specified unit. This request is initiated by an userspace application (IOCTL). | ||
+ | |||
+ | **Input parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 14 | Long |Pointer to a buffer that' | ||
+ | | 18 | Long |Buffer size | | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | ===== 0x13 - Generic IOCTL ===== | ||
+ | |||
+ | **Command ID :** 0x13 (C_GENIOCTL) | ||
+ | |||
+ | **Availability :** Block/ | ||
+ | |||
+ | **Description :** Perform a IOCTL command understood only by the driver and an userspace program. | ||
+ | |||
+ | **Input parameters :** | ||
+ | |||
+ | ^ Position | ||
+ | | 14 | Long |Optional pointer to a buffer. That buffer is totally specific to the IOCTL command ID. | | ||
+ | | 18 | Word |IOCTL command ID. There is no restriction to this value. | ||
+ | |||
+ | **Output parameters :** none | ||
+ | |||
+ | ====== Extend command code ====== | ||
+ | |||
+ | These following request command codes are only performed when the driver header have the " | ||
+ | |||
+ | I actually do not know very much about them but they seems to be really filesystem level. | ||
+ | |||
+ | Here is all known command ID : | ||
+ | |||
+ | * 0x40 - CR_INIT | ||
+ | * 0x41 - CR_SEARCH_DIR | ||
+ | * 0x42 - CR_CREATE_DIR | ||
+ | * 0x43 - CR_DELETE_DIR | ||
+ | * 0x44 - CR_RENAME_FILE | ||
+ | * 0x45 - CR_DELETE_FILE | ||
+ | * 0x46 - CR_CHMOD | ||
+ | * 0x47 - CR_FILES | ||
+ | * 0x48 - CR_NFILES | ||
+ | * 0x49 - CR_CREATE | ||
+ | * 0x4A - CR_OPEN | ||
+ | * 0x4B - CR_CLOS | ||
+ | * 0x4C - CR_READ | ||
+ | * 0x4D - CR_WRITE | ||
+ | * 0x4E - CR_SEEK | ||
+ | * 0x4F - CR_TIMEMOD | ||
+ | * 0x50 - CR_GETCAP | ||
+ | * 0x51 - CR_CONTROL | ||
+ | * 0x52 - CR_BUILD_BPB | ||
+ | * 0x53 - CR_IOCTL_IN | ||
+ | * 0x54 - CR_IOCTL_OUT | ||
+ | * 0x55 - CR_IOCTL_SPECIAL | ||
+ | * 0x56 - CR_ABORT | ||
+ | * 0x57 - CR_MEDIA_CHECK | ||
+ | * 0x58 - CR_LOCK | ||
+ | |||
+ | I do have parameters. I will write them later. | ||
+ | |||
+ | |||
+ | ====== BIOS Parameter Block (BPB) ====== | ||
+ | |||
+ | I will not explain this structure as there is plenty of informations about it on the internet. | ||
+ | |||
+ | Starting from wikipedia : http:// | ||
+ | |||
+ | Just read everything you can about FAT12 and FAT16. 95% of these also apply to Human68k. | ||
+ | |||
+ | Most of difference is the byte ordering, which is big endian instead of little endian. The structure is also a bit different. | ||
+ | |||
+ | From my ddk.h file : | ||
+ | |||
+ | < | ||
+ | struct bpb { | ||
+ | UWORD bpb_nbyte; | ||
+ | UBYTE bpb_nsector; | ||
+ | UBYTE bpb_nfat; | ||
+ | UWORD bpb_nreserved; | ||
+ | UWORD bpb_ndirent; | ||
+ | UWORD bpb_nsize; | ||
+ | UBYTE bpb_mdesc; | ||
+ | UBYTE bpb_nfsect; | ||
+ | ULONG bpb_huge; | ||
+ | }; | ||
+ | </ | ||
+ | |||
+ | See ? Only the " |
x68000/writing_drivers.1404985810.txt.gz · Last modified: 2019/08/27 20:44 (external edit)