ceatadrv Code
Brought to you by:
neozeed2
What is a device driver? The hard disk device is a block device. What this means is that data is transfered to/from the device in chunks, or blocks, of data. In the case of a hard disk, this block is 512 bytes. A different type of device is a character device, such as the serial port. A character device transfers data one byte at a time. Why use a device driver? A block device driver is implemented in the form of a dynamically linked library, or dll. This driver directly controls the block device. It is the OS's interface to the hardware. After the device is loaded all subsequent access to the hard disk are performed through the device driver. The benefits of this implementation are two fold. First, there is a single well defined interface to the hardware. Second, there is a single point of control for the device. Imagine the problems that would exist if each user application required access to a hard disk and there were no unified driver. The device would suffer from multiple commands at the same time causing problems from data corruption to system crashes. Also imagine the headache in programming modules to control the same device in every application that makes use of it. What device drivers are required for controlling a Hard Disk? To implement a hard disk driver in Windows CE 2.12 two separate drivers are required. The Block Device Driver (BDD) is necessary to control the disk and a File System Driver (FSD) is necessary to manage media storage on the device. Windows CE's philosophy behind block devices requires that a FSD be associated with a BDD. This is yet another abstraction to handling the device thereby making the OS's job much easier. (unfortunately an efficient implementation isn't always the result of an easy task) What does a Block Device driver look like? Let's step it up a notch.. The BDD dll must contain the following exported routines: xxx_Deinit xxx_Init xxx_Open xxx_Close xxx_Read xxx_Write xxx_Seek xxx_IOControl xxx_PowerDown xxx_PowerUp Replace xxx with letters of your own to refer to your particular device. For instance, because our driver started out as a CDROM driver (and can still function as a BDD for a cdrom) we chose CDROM. Also, note that 'must' is really 'should' or perhaps in some cases 'should not'. This is because most of the routines listed above were obseleted when Windows CE decided to copy UNIXs implementation of a device driver. Interesting how ioctl() in UNIX and xxx_IOControl() aren't really that far apart in name.. nor in function. With this 'new' implementation a control word is passed to IOControl which instructs IOControl on what to do whether it be a read, write, open, or whatever.. The read and write codes of xxx_IOControl() are of particular interest here. It is these routines that we wrote to provide HD access. A function in Diskio.c, namely pdin(), performs the steps for PIO as defined in the ATA protocol for reads and writes. In fact, all the direct I/O routines are in Diskio.c whilst the xxx_??() routines are located in System.c. What about the FSD? When we started our goal was to implement a CDROM device driver. After much frustration with the documentation we decided that creating our own FSD for ISO9660 was not practical. In fact, we watched a slide presentation given by Windows which suggested that implementing a FSD might be troublesome without a reference. I guess they too don't put much stock in their documentation. Thus, we retargeted our design for an ATA hard disk, which is much simpler I might add.. How do you load the device driver? Our method for loading a BDD was to call RegisterDevice(). This registers the device with the Device Manager which begins the initialization process for the device by loading the driver's .dll file and calling xxx_Init(). It is here that the BDD initializes the physical device. In our case, we read some information reom the system registry file which was set by the loader program that called RegisterDevice(). This program is called cecdrdrv (see ceatadrv.c). You specify the physical location of the device as an argument to this program. For example, if the hard disk is the Master device on the Secondary IDE interface you would type: cecdrdrv s0 where the 's' stands for Secondary and the '0' stands for Master. After the call to RegisterDevice() the Device Manager calls xxx_Init() which after device initialization returns. The Device Manager then calls xxx_IOControl() with DISK_IOCTL_INITIALIZED. The BDD then loads the FSD. In our case we loaded the infamous fatfs.dll. At this point the FSD is in control and can make disk accesses even before it returns from the LoadFSD() routine!! Therefore all this code must be re-entrant. Now that the OS is in control All disk access will come from the FSD. The first thing that will happen is the FSD will attempt to mount the device. This involves formatting if necessary, else the driver is up and running. One thing to be aware of is that the documentation for the LoadFSD() routine specifies that it will always return a success indication regardless of whether it was successfull or not. So, the BDD could be orphaned and it would never know... must be a feature. Implementation: How to get this thing working Build a MAXALL CE kernel. Add a new project (ceatadrv) to the workspace Add ceatadrv.c file to the source Make ceatadrv.exe Add a new dll project to the workspace (atadrv) Add atadrv.c and associated source and def files to the project Make atadrv.dll Modify the platform's project.bib file Add the following at the top, under the files section ceatadrv.exe $(_FLATRELEASEDIR)\ceatadrv.exe NK U atadrv.dll $(_FLATRELEASEDIR)\atadrv.dll NK U Build the project and download NK.bin From the shell run ceatadrv s0 Well, this is the end of the discussion. I hope you have enough information to load and run the BDD for the ATA Hard Disk...