Create a new test directory in the Ubuntu user folder. For example, my linux source directory is: / home/ql/linux/H3/linux.
The directory where the driver and application source code are placed is / home/ql/linux/H3/MyDriver/01_chrdevbase
Then add 3 files in this directory:
Drive source file
chrdevbase.c
#include <linux/types.h> #include <linux/kernel.h> #include <linux/delay.h> #include <linux/ide.h> #include <linux/init.h> #include <linux/module.h> /*************************************************************** Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved. file name : chrdevbase.c author : Zuo Zhongkai edition : V1.0 describe : chrdevbase driver file. other : nothing Forum : www.openedv.com journal : First version v1.0 created by Zuo Zhongkai on January 30, 2019 ***************************************************************/ #define CHRDEVBASE_MAJOR two hundred /* Main equipment No*/ #define CHRDEVBASE_NAME "chrdevbase" /* Device name*/ static char readbuf[100]; /* Read buffer */ static char writebuf[100]; /* Write buffer */ static char kerneldata[] = {"kernel data!"}; /* * @description : open device * @param - inode : inode passed to driver * @param - filp : The device file has a file structure called private_ Member variable of data * Generally, private is used when open ing_ Data points to the device structure. * @return : 0 success; Other failures */ static int chrdevbase_open(struct inode *inode, struct file *filp) { //printk("chrdevbase open!\r\n"); return 0; } /* * @description : Read data from device * @param - filp : Device file to open (file descriptor) * @param - buf : Data buffer returned to user space * @param - cnt : Length of data to read * @param - offt : Offset relative to the first address of the file * @return : The number of bytes read. If it is negative, it indicates that the read failed */ static ssize_t chrdevbase_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt) { int retvalue = 0; /* Send data to user space */ memcpy(readbuf, kerneldata, sizeof(kerneldata)); retvalue = copy_to_user(buf, readbuf, cnt); if(retvalue == 0){ printk("kernel senddata ok!\r\n"); }else{ printk("kernel senddata failed!\r\n"); } //printk("chrdevbase read!\r\n"); return 0; } /* * @description : Write data to device * @param - filp : A device file that represents an open file descriptor * @param - buf : Data to write to device * @param - cnt : Length of data to write * @param - offt : Offset relative to the first address of the file * @return : The number of bytes written. If it is negative, it indicates that the write failed */ static ssize_t chrdevbase_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt) { int retvalue = 0; /* Receive the data passed from user space to the kernel and print it out */ retvalue = copy_from_user(writebuf, buf, cnt); if(retvalue == 0){ printk("kernel recevdata:%s\r\n", writebuf); }else{ printk("kernel recevdata failed!\r\n"); } //printk("chrdevbase write!\r\n"); return 0; } /* * @description : Turn off / release the device * @param - filp : Device file to close (file descriptor) * @return : 0 success; Other failures */ static int chrdevbase_release(struct inode *inode, struct file *filp) { //printk("chrdevbase release!\r\n"); return 0; } /* * Device operation function structure */ static struct file_operations chrdevbase_fops = { .owner = THIS_MODULE, .open = chrdevbase_open, .read = chrdevbase_read, .write = chrdevbase_write, .release = chrdevbase_release, }; /* * @description : Drive entry function * @param : nothing * @return : 0 success; Other failures */ static int __init chrdevbase_init(void) { int retvalue = 0; /* Register character device driver */ retvalue = register_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME, &chrdevbase_fops); if(retvalue < 0){ printk("chrdevbase driver register failed\r\n"); } printk("chrdevbase init!\r\n"); return 0; } /* * @description : Drive exit function * @param : nothing * @return : nothing */ static void __exit chrdevbase_exit(void) { /* Unregister character device driver */ unregister_chrdev(CHRDEVBASE_MAJOR, CHRDEVBASE_NAME); printk("chrdevbase exit!\r\n"); } /* * Specify the above two functions as the driver's entry and exit functions */ module_init(chrdevbase_init); module_exit(chrdevbase_exit); /* * LICENSE And author information */ MODULE_LICENSE("GPL"); MODULE_AUTHOR("zuozhongkai");
Application source file
chrdevbaseApp.c
#include "stdio.h" #include "unistd.h" #include "sys/types.h" #include "sys/stat.h" #include "fcntl.h" #include "stdlib.h" #include "string.h" /*************************************************************** Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved. file name : chrdevbaseApp.c author : Zuo Zhongkai edition : V1.0 describe : chrdevbase test APP. other : Usage:. / chrdevbase / dev / chrdevbase < 1 > | < 2 > argv[2] 1:read file argv[2] 2:Write file Forum : www.openedv.com journal : First version v1.0 created by Zuo Zhongkai on January 30, 2019 ***************************************************************/ static char usrdata[] = {"usr data!"}; /* * @description : main main program * @param - argc : argv Number of array elements * @param - argv : Specific parameters * @return : 0 success; Other failures */ int main(int argc, char *argv[]) { int fd, retvalue; char *filename; char readbuf[100], writebuf[100]; if(argc != 3){ printf("Error Usage!\r\n"); return -1; } filename = argv[1]; /* Open driver file */ fd = open(filename, O_RDWR); if(fd < 0){ printf("Can't open file %s\r\n", filename); return -1; } if(atoi(argv[2]) == 1){ /* Read data from driver file */ retvalue = read(fd, readbuf, 50); if(retvalue < 0){ printf("read file %s failed!\r\n", filename); }else{ /* If the reading is successful, print out the successfully read data */ printf("read data:%s\r\n",readbuf); } } if(atoi(argv[2]) == 2){ /* Write data to device driver */ memcpy(writebuf, usrdata, sizeof(usrdata)); retvalue = write(fd, writebuf, 50); if(retvalue < 0){ printf("write file %s failed!\r\n", filename); } } /* Turn off the device */ retvalue = close(fd); if(retvalue < 0){ printf("Can't close file %s\r\n", filename); return -1; } return 0; }
Makefile
KERNELDIR := /home/ql/linux/H3/linux CURRENT_PATH := $(shell pwd) obj-m := chrdevbase.o build: kernel_modules kernel_modules: make ARCH=arm CROSS_COMPILE=arm-linux- -C $(KERNELDIR) M=$(CURRENT_PATH) modules clean: make ARCH=arm CROSS_COMPILE=arm-linux- -C $(KERNELDIR) M=$(CURRENT_PATH) clean
compile
After the above three files are added:
Compile driver
Enter the directory where the source code of the driver file is located and compile the driver:
cd /home/ql/linux/H3/MyDriver/01_chrdevbase make
The ko file has been compiled.
Compiling applications
Recompile the application and execute
arm-linux-gcc chrdevbaseApp.c -o chrdevbaseApp
After compilation, an executable program called chrdevbaseAPP will be generated. Enter the file chrdevbaseApp command to view the file information of chrdevbaseAPP:
Test run on development board
Transfer the compiled chrdevbase.ko and chrdevbaseApp to the development board through SCP.
scp chrdevbase.ko root@192.168.0.103:/lib/modules/4.14.111/ scp chrdevbaseApp root@192.168.0.103:/lib/modules/4.14.111/
Use the following command to change the console message level:
echo 5 >/proc/sys/kernel/printk cat /proc/sys/kernel/printk
Driver module loading
Enter the following command to load the chrdevbase.ko driver file:
insmod chrdevbase.ko
You can see the output of "chrdevbase init!", which is the output of the driver entry function, indicating that the driver module is loaded successfully.
Enter the lsmod command to view the modules existing in the current system:
Enter the cat /proc/devices command to check whether there is a chrdevbase device in the current system:
It can be seen that there is a chrdevbase device in the current system. The main device number is 200, which is consistent with the main device number we set.
Application testing
To load the driver successfully, you need to create a corresponding device node file in the / dev directory. The application completes the operation of the specific device by operating the device node file. Enter the following command to create the / dev/chrdevbase device node file:
mknod /dev/chrdevbase c 200 0
Where "mknod" is the command to create a node, "/ dev/chrdevbase" is the node file to be created, "c" indicates that this is a character device, "200" is the primary device number of the device, and "0" is the secondary device number of the device. After creation, the file / dev/chrdevbase will exist. You can use the ls /dev/chrdevbase -l command to view it.
Everything under Linux is a file, so you can read, write, open and close the file like under windows. The operation of files is implemented in the application program. Here, you can run it directly. First, read and enter the following command:
./chrdevbaseApp /dev/chrdevbase 1
Next, test the write operation to the chrdevbase device, and enter the following command:
./chrdevbaseApp /dev/chrdevbase 2
Unloading the driver module
rmmod chrdevbase.ko