Linux分为内核态和用户态
硬件设备驱动在内核态,硬件设备驱动可以理解为内核态提供的硬件设备的API,供用户态调用。
一、代码
hello.c
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Hcamal");
int hello_init(void)
{
printk(KERN_INFO "Hello World\n");
return 0;
}
void hello_exit(void)
{
printk(KERN_INFO "Goodbye World\n");
}
module_init(hello_init);
module_exit(hello_exit);
二、Makefile
Makefile
obj-m := hello.o
KERN_DIR ?= /usr/src/linux-headers-$(shell uname -r)/
PWD := $(shell pwd)
all:
make -C $(KERN_DIR) M=$(PWD) modules
clean:
rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
三、编译运行
(base) lin@ubuntu:~/code$ uname -r
5.0.0-23-generic
(base) lin@ubuntu:~/code$ sudo insmod hello.ko
(base) lin@ubuntu:~/code$ rmmod hello
rmmod: ERROR: ../libkmod/libkmod-module.c:793 kmod_module_remove_module() could not remove 'hello': Operation not permitted
rmmod: ERROR: could not remove module hello: Operation not permitted
(base) lin@ubuntu:~/code$ sudo rmmod hello
(base) lin@ubuntu:~/code$ dmesg |tail -1
[ 2797.874962] Goodbye World
(base) lin@ubuntu:~/code$ dmesg |tail -2
[ 2721.631195] Hello World
[ 2797.874962] Goodbye World
(base) lin@ubuntu:~/code$
四、API
/dev/xxx/read|write|fseek
通过注册设备和设备回调来提供API
file_operatetors
staticstructfile_operations hello_driver_fops =
{
.owner = THIS_MODULE,
.read = hello_read,
.write = hello_write,
};
hello.c
#include <linux/init.h>
#include <linux/module.h>
#include "hello_device.h"
#include "hello_device.c"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("Hcamal");
int hello_init(void)
{
printk(KERN_INFO "Hello World\n");
register_hello_device();
return 0;
}
void hello_exit(void)
{
printk(KERN_INFO "Goodbye World\n");
unregister_hello_device();
}
module_init(hello_init);
module_exit(hello_exit);
hello_device.h
#ifndef HELLO_DEVICE_FILE_H_
#define HELLO_DEVICE_FILE_H_
#include <linux/compiler.h> /* __must_check */
__must_check int register_hello_device(void); /* 0 if Ok*/
void unregister_hello_device(void);
#endif //HELLO_DEVICE_FILE_H_
hello_device.c
#include "hello_device.h"
#include <linux/fs.h> /* file stuff */
#include <linux/kernel.h> /* printk() */
#include <linux/errno.h> /* error codes */
#include <linux/module.h> /* THIS_MODULE */
#include <linux/cdev.h> /* char device stuff */
#include <asm/uaccess.h> /* copy_to_user() */
static const char g_s_Hello_World_string[] = "Hello world from kernel mode!\n\0";
static const ssize_t g_s_Hello_World_size = sizeof(g_s_Hello_World_string);
/*===============================================================================================*/
static ssize_t hello_read(
struct file *file_ptr
, char __user *user_buffer
, size_t count
, loff_t *possition)
{
printk( KERN_NOTICE "hello-driver: Device file is read at offset = %i, read bytes count = %u"
, (int)*possition
, (unsigned int)count );
if( *possition >= g_s_Hello_World_size )
return 0;
if( *possition + count > g_s_Hello_World_size )
count = g_s_Hello_World_size - *possition;
if( raw_copy_to_user(user_buffer, g_s_Hello_World_string + *possition, count) != 0 )
return -EFAULT;
*possition += count;
return count;
}
/*===============================================================================================*/
static struct file_operations hello_driver_fops =
{
.owner = THIS_MODULE,
.read = hello_read,
};
static int hello_major_number = 0;
static const char device_name[] = "hello-driver";
/*===============================================================================================*/
int register_hello_device(void)
{
int result = 0;
printk( KERN_NOTICE "hello-driver: register_device() is called." );
result = register_chrdev( 0, device_name, &hello_driver_fops );
if( result < 0 )
{
printk( KERN_WARNING "hello-driver: can\'t register character device with errorcode = %i", result );
return result;
}
printk( KERN_NOTICE "hello-driver: register_device() is called %i." , result);
hello_major_number = result;
printk( KERN_NOTICE "hello-driver: registered character device with major number = %i and minor numbers 0...255"
, hello_major_number );
return 0;
}
/*-----------------------------------------------------------------------------------------------*/
void unregister_hello_device(void)
{
printk( KERN_NOTICE "hello-driver: unregister_device() is called" );
if(hello_major_number != 0)
{
unregister_chrdev(hello_major_number, device_name);
}
}
(base) lin@ubuntu:~/code$ vi /proc/devices
(base) lin@ubuntu:~/code$ cat /proc/devices |grep hello-driver
239 hello-driver
(base) lin@ubuntu:~/code$ mknod /dev/simple-driver c 239 0
mknod: /dev/simple-driver: Permission denied
(base) lin@ubuntu:~/code$ sudo mknod /dev/hello-driver c 239 0
(base) lin@ubuntu:~/code$ ls /dev |grep hello
hello-driver
(base) lin@ubuntu:~/code$ cat /dev/hello-driver
Hello world from kernel mode!
reference: https://medium.com/@knownsec404team/how-to-develop-linux-driver-from-scratch-cc143e0c08a1