模块式注册,不是直接把驱动编译进内核,而是生成模块,需要的再加载到内核中去。
https://blog.csdn.net/u011425939/article/details/80552143
上篇文章是用编译进内核的方法生成启动,此次用模块的方式到达同样的作用。
1、驱动程序文件itop4412_hello.c
#include <linux/init.h>
#include <linux/module.h>
/*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>
#define DRIVER_NAME "hello_device"
#define DEVICE_NAME "hello"
MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");
static long hello_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
printk("cmd is %d,arg is %d\n",cmd,arg);
return 0;
}
static int hello_release(struct inode *inode, struct file *file){
printk(KERN_EMERG "hello release\n");
return 0;
}
static int hello_open(struct inode *inode, struct file *file){
printk(KERN_EMERG "hello open\n");
return 0;
}
static struct file_operations hello_ops = {
.owner = THIS_MODULE,
.open = hello_open,
.release = hello_release,
.unlocked_ioctl = hello_ioctl,
};
static struct miscdevice hello_dev = {
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &hello_ops,
};
static int hello_probe(struct platform_device *pdv){
printk(KERN_EMERG "\tinitialized\n");
misc_register(&hello_dev);
return 0;
}
static int hello_remove(struct platform_device *pdv){
printk(KERN_EMERG "\tremove\n");
misc_deregister(&hello_dev);
return 0;
}
static void hello_shutdown(struct platform_device *pdv){
;
}
static int hello_suspend(struct platform_device *pdv,pm_message_t pmt){
return 0;
}
static int hello_resume(struct platform_device *pdv){
return 0;
}
struct platform_driver hello_driver = {
.probe = hello_probe,
.remove = hello_remove,
.shutdown = hello_shutdown,
.suspend = hello_suspend,
.resume = hello_resume,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
}
};
static int hello_init(void)
{
int DriverState;
printk(KERN_EMERG "HELLO WORLD enter!\n");
DriverState = platform_driver_register(&hello_driver);
printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
return 0;
}
static void hello_exit(void)
{
printk(KERN_EMERG "HELLO WORLD exit!\n");
platform_driver_unregister(&hello_driver);
}
module_init(hello_init);
module_exit(hello_exit);
2、编译makefile
#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件itop4412_hello.o
obj-m += itop4412_hello.o
#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录work/itop-4412/iTop4412_Kernel_3.0下并解压的
KDIR := work/itop-4412/iTop4412_Kernel_3.0
#当前目录变量
PWD ?= $(shell pwd)
#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/work/itop-4412/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
make -C $(KDIR) M=$(PWD) modules
#make clean执行的操作是删除后缀为o的文件
clean:
rm -rf *.o
3、编译 make
生成文件 itop4412_hello.ko
4、加载模块
[root@iTOP-4412]# insmod itop4412_hello.ko
[ 894.658700] HELLO WORLD enter!
[ 894.660410] initialized
[ 894.666200] DriverState is 0
[root@iTOP-4412]#
ls /dev 看已经生成了设备结点hello
[root@iTOP-4412]# ls /dev/
AGPS ion ppp tty3
HPD keychord ptmx tty4
adc kmem pts ttyGS0
alarm kmsg ram0 ttyGS1
android_adb leds ram1 ttyGS2
ashmem log ram10 ttyGS3
buzzer_ctl loop0 ram11 ttyS0
console loop1 ram12 ttyS1
cpu_dma_latency loop2 ram13 ttyS2
exynos-mem loop3 ram14 ttyS3
fb0 loop4 ram15 ttySAC0
fb1 loop5 ram2 ttySAC1
fb10 loop6 ram3 ttySAC2
fb11 loop7 ram4 ttySAC3
fb2 mali ram5 uinput
fb3 mapper ram6 ump
fb4 max485_ctl_pin ram7 urandom
fb5 mem ram8 usb_accessory
fb6 mmcblk0 ram9 usbdev1.1
fb7 mmcblk0p1 random usbdev1.2
fb8 mmcblk0p2 rc522 usbdev1.3
fb9 mmcblk0p3 relay_ctl video0
fimg2d mmcblk0p4 root video1
full mmcblk1 rtc0 video11
fuse mmcblk1p1 rtc1 video12
gps mmcblk1p2 s3c-mem video16
hello mmcblk1p3 s3c-mfc video2
i2c-0 mmcblk1p4 shm video20
i2c-1 mtp_usb snd video3
i2c-3 network_latency srp watchdog
i2c-4 network_throughput srp_ctrl xt_qtaguid
i2c-5 null tty zero
i2c-7 pmem tty1
input pmem_gpu1 tty2
5、查找模块
[root@iTOP-4412]# lsmod
itop4412_hello 1869 0 - Live 0xbf008000
[root@iTOP-4412]#
6、卸载模块
[root@iTOP-4412]# rmmod itop4412_hello
[ 967.248981] HELLO WORLD exit!
[ 967.250524] remove
[root@iTOP-4412]#