elks-enhanced
public
Read
Owner: themaster
Branch: master
Commits: 6893
Updated: 2026-04-19 00:15
Git CLI clone URL
git clone https://www.xt-emporium.com/git/elks-enhanced.git
Fullscreen desktop URL
Code
Commits
History
Branches
Bug Reports
Discussions
Compare
Settings
elks-enhanced
/
Documentation
/
html
/
technical
/
kernel_mode_device_drivers.html
File editor
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=windows-1252"> <TITLE></TITLE> <META NAME="GENERATOR" CONTENT="OpenOffice 4.1.2 (Win32)"> <META NAME="AUTHOR" CONTENT="Georg Potthast"> <META NAME="CREATED" CONTENT="20170105;19172240"> <META NAME="CHANGEDBY" CONTENT="Georg Potthast"> <META NAME="CHANGED" CONTENT="20170304;11433543"> <STYLE TYPE="text/css"> <!-- @page { margin: 2cm } TD P { margin-bottom: 0cm } P { margin-bottom: 0.21cm } PRE.cjk { font-family: "NSimSun", monospace } H2 { margin-bottom: 0.21cm } H2.western { font-family: "Arial", sans-serif; font-size: 14pt; font-style: italic } H2.cjk { font-family: "Microsoft YaHei"; font-size: 14pt; font-style: italic } H2.ctl { font-family: "Lucida Sans"; font-size: 14pt; font-style: italic } A:link { so-language: zxx } --> </STYLE> </HEAD> <BODY LANG="de-DE" DIR="LTR"> <TABLE WIDTH=718 BORDER=0 CELLPADDING=4 CELLSPACING=0 STYLE="page-break-before: always"> <COL WIDTH=710> <TR> <TD WIDTH=710 VALIGN=TOP> <H2 CLASS="western" STYLE="font-style: normal">Writing kernel mode drivers for ELKS</H2> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">Like most alternative operating systems, ELKS is missing drivers for many peripherals. Therefore this text describes to write additional drivers.</FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">As a proof of concept, the 'hellodev' driver will be implemented now:</FONT></P> <PRE CLASS="western">/* * hello driver for ELKS kernel */ #include <linuxmt/kernel.h> /* printk() */ #include <linuxmt/fs.h> /* file_operations struct */ #include <string.h> #define HELLO_DEVICE_NAME "hellodev" #define HELLO_MAJOR 11 static char message[256]; char *msgptr = message; static int hello_write(struct inode *inode, struct file *file, char* buf, int len) { memcpy_fromfs(message,buf,len); printk("hellodev: hello_write() called\n"); return 0; } static int hello_read(struct inode *inode, struct file *file, char* buf, int len) { memcpy_tofs(buf, message, len); printk("hellodev: hello_read() called\n"); return len; } static int hello_open(struct inode *inode, struct file *file) { printk("hellodev: hello_open() called\n"); return 0; } static void hello_release(struct inode *inode, struct file *file) { printk("hellodev: hello_release() called\n"); return; } static struct file_operations hello_fops = { NULL, /* lseek */ hello_read, /* read */ hello_write, /* write */ NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ hello_open, /* open */ hello_release /* release */ #ifdef BLOAT_FS , NULL, /* fsync */ NULL, /* check_media_type */ NULL /* revalidate */ #endif }; void hello_init(void) { printk("hellodev: hello_init() called\n"); /* register device */ if (register_chrdev(HELLO_MAJOR, HELLO_DEVICE_NAME, &hello_fops)) printk("hellodev: unable to register\n"); }</PRE><P STYLE="margin-bottom: 0.5cm"> <FONT FACE="Arial, sans-serif">This driver just implements the functions hello_init(), hello_open(), hello_read(), hello_write() and hello_release(). When these functions are called it outputs a message using the printk() statement. This is the equivalent for printf() in kernel code. Also the functions memcpy_fromfs() and memcpy_tofs() are used. The kernel will for security reasons not accept pointers from userspace which may be faulty. Therefore you have to use these functions. For single chars there are equivalent functions available called get_user_char() and put_user_char(). You will also not be able to use inportb() and outportb() functions, use the inb() and inb_p() or out() and out_p() functions instead. The „_p“ versions insert a small pause or delay before returning to support slower devices.</FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">When the driver is loaded the kernel will call hello_init() and the hellodev driver will execute the register_chrdev() function. This function contains the device name which will appear in the /dev directory and a pointer to the file_operations structure called hello_ops. In there the kernel will find the addresses of the functions defined in the driver.</FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">The kernel identifies the driver by its unique the major number. In our demo driver we have included these macros in the code: </FONT> </P> <PRE CLASS="western">#define HELLO_DEVICE_NAME "hellodev" #define HELLO_MAJOR 11</PRE><P STYLE="margin-bottom: 0.5cm"> <FONT FACE="Arial, sans-serif">Usually in ELKS major numbers are defined in the elks/include/linuxmt/major.h file which the drivers include. Refer to the major numbers in that file to determine the next available major number. That file also needs to be changed. Increase the maximum number of char devices by 1:</FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">#define MAX_CHRDEV 12</FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">Put the code above as the hellodev.c file into the elks/arch/i86/drivers/char/ directory and add it to the Makefile in this directory:</FONT></P> <PRE CLASS="western"> OBJS = init.o mem.o ntty.o meta.o tcpdev.o pty.o lp.o <B>hellodev.o</B> </PRE><P STYLE="margin-bottom: 0.5cm"> <FONT FACE="Arial, sans-serif">Also edit the init.c file:</FONT></P> <PRE CLASS="western">void chr_dev_init(void) { #if 1 hello_init(); #endif #ifdef CONFIG_CHAR_DEV_RS rs_init();</PRE><P STYLE="margin-bottom: 0.5cm"> <FONT FACE="Arial, sans-serif"><FONT SIZE=3>Normally, you would define a macro in the elks/arch/i86/defconfig file which can be modified with „menuconfig“ and modify the files elks/arch/i86/drivers/char/config.in plus Documentation/Configure.help.</FONT></FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif"><FONT SIZE=3>Further, the hello_init() function has to be declared in the elks/include/linuxmt/init.h file:</FONT></FONT></P> <PRE CLASS="western">extern void xtk_init(void); extern void hello_init(void); extern void init_console(void);</PRE><P STYLE="margin-bottom: 0.5cm"> <FONT FACE="Arial, sans-serif"><FONT SIZE=3>To load the driver simply add it after the last character device in the image/Make.devices script:</FONT></FONT></P> <PRE CLASS="western"> # CGATEXT ifdef CONFIG_CHAR_DEV_CGATEXT $(MKDEV) /dev/cgatext c 10 0 endif $(MKDEV) /dev/hellodev c 11 0 </PRE><P STYLE="margin-bottom: 0.5cm"> <FONT FACE="Arial, sans-serif"><FONT SIZE=3>The letter „c“ stands for character driver while the number 11 is the major number and zero the minor number. Be careful to use the major number we defined above.</FONT></FONT> </P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif"><FONT SIZE=3>To sum it up, you added hellodev.c into the elks/arch/i86/drivers/char directory and modified init.c and the Makefile in there. Also you modified major.h and init.h in the elks/include/linuxmt directory and the file Make.devices in the image directory.</FONT></FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">Now you can compile ELKS again and it will include the hellodev driver and load it. If you enter „ls /dev“ you will see a device node called hellodev.</FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">To test this driver use this program which you may call drvtest.c:</FONT></P> <PRE CLASS="western">#include<stdio.h> #include<stdlib.h> #include<errno.h> #include<fcntl.h> #define BUFFER_LENGTH 256 static char receive[BUFFER_LENGTH]; int main(){ int ret, fd; char stringToSend[BUFFER_LENGTH]; printf("Starting device test code example...\n"); fd = open("/dev/hellodev", O_RDWR); if (fd < 0){ perror("Failed to open the device..."); return errno; } printf("Type in a short string to send to the kernel module:\n"); scanf("%s", stringToSend); // Read in a string printf("Writing message to the device [%s].\n", stringToSend); ret = write(fd, stringToSend, strlen(stringToSend)); if (ret < 0){ perror("Failed to write the message to the device."); return errno; } printf("Now reading the string back from the device...\n"); ret = read(fd, &receive[0], BUFFER_LENGTH); if (ret < 0){ perror("Failed to read the message from the device."); return errno; } printf("The received message is: [%s]\n", receive); return 0; }</PRE><P STYLE="margin-bottom: 0.5cm"> <FONT FACE="Arial, sans-serif">To compile this program enter „ ia16-elf-gcc drvtest.c -o drvtest -melks-libc -mcmodel=small“ and e.g. copy the executable drvtest to the image file using a loop device.</FONT></P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">Here are some additional notes how ELKS drivers work describing the concepts used above taken from the fs.txt file:<BR><BR>The inode->i_op pointer is initialised in the function which reads in an inode, e.g. V1_minix_read_inode, and its contents depend on the type of file. If the node is a character or block device, i_op points to chrdev_inode_operations or blkdev_inode_operations respectively. These tables are declared in devices.c and contain pointers just to the respective "open" functions, chrdev_open and blkdev_open. <BR><BR>When the user opens one of these inodes, the kernel calls the open function and passes in a pointer to the relevant "struct file" record. The fops pointer in this record is copied from chrdevs[major].fops or blkdevs[major].fops, which was set up when the device was initialised and registered itself.<BR><BR>So, in the case of the console for example, the file record defined as dircon_ops (see drivers/char/dircon.c) has pointers to the functions to perform I/O to the console. <BR><BR>In the case of block devices, the read() and write() functions *don't* point to device-specific read and write functions; rather, they point to the generic functions block_read() and block_write() in block_dev.c. These take care of caching blocks, part-block reads and writes etc.</FONT></P> <P STYLE="margin-bottom: 0.5cm"><BR><BR> </P> <P STYLE="margin-bottom: 0.5cm"><FONT FACE="Arial, sans-serif">4<SUP>th</SUP> of March 2017 Georg Potthast</FONT></P> <P><BR> </P> </TD> </TR> </TABLE> <P><BR><BR> </P> </BODY> </HTML>
Commit message
This repository is read-only for this account.
Repository snapshot
Current branch
master
Visibility
public
Your access
Read
Remote
Configured
File activity
View file history