ARM驱动学习之21_字符驱动
操作步骤:
cpp
file_operations中的函数比较多,
选取用的比较多的函数简单介绍,
后
面的驱动教程中调用了对应的函数
• int (*open) (struct inode *, struct file *)
-- 打开函数
• int (*release) (struct inode *, struct file *)
-- 释放close函数
• long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long)
-- io控制函数
• ssize_t (*read) (struct file *, char __user *, size_t, loff_t *)
-- 读函数
• ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *)
-- 写函数
• loff_t (*llseek) (struct file *, loff_t, int)
-- 定位函数
1.修改文件名为char_driver并修改Makefile里面的文件。
定义函数如下:
/*打开操作*/
static int chardevnode_open(struct inode * inode,struct file * file){
printk(KERN_EMERG "chardevnode_open is opened! \n");
return 0;
}
/*关闭操作*/
static int chardevnode_release(struct inode *inode,struct file *file){
printk(KERN_EMERG "chardevnode_release is release! \n");
return 0;
}
/*IO操作*/
static long chardevnode_ioctl (struct file *file, unsigned int cmd, unsigned long arg){
printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %d,arg is %d \n",cmd,arg);
return 0;
}
static ssize_t chardevnode_read (struct file *file , char __user *buf, size_t count, loff_t *f_ops){
return 0;
}
static ssize_t chardevnode_write (struct file *file , const char __user *buf, size_t count, loff_t *f_ops){
return 0;
}
static loff_t chardevnode_llseek (struct file *file , loff_t offset, int ence){
return 0;
}
2.在struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = chardevnode_open,
.release = chardevnode_release,
.unlocked_ioctl = chardevnode_ioctl,
.read = chardevnode_read,
.write = chardevnode_write,
.llseek = chardevnode_llseek,
};
2.修改invoke_hello.c文件:
cpp
1.将"invoke_hello.c"改为"invoke_char_driver.c"
在文件中添加如下内容:
char *hello_node0 = "/dev/chardevnode0";
char *hello_node1 = "/dev/chardevnode1";
2.修改函数名为hello_node0 和 hello_node1;
if((fd = open(hello_node0,O_RDWR|O_NDELAY)) < 0)
{
printf();
}
close(fd);
编译应用命令如下
-- arm-none-linux-gnueabi-gcc -o invoke_char_driver invoke_char_driver.c -static
代码,设备节点:
cpp
#include <linux/init.h>
/*包含初始化宏定义的头文件,代码中的module_init和module_exit在此文件中*/
#include <linux/module.h>
/*包含初始化加载模块的头文件,代码中的MODULE_LICENSE在此头文件中*/
/*定义module_param module_param_array的头文件*/
#include <linux/moduleparam.h>
/*定义module_param module_param_array中perm的头文件*/
#include <linux/stat.h>
/*字符设备函数*/
#include <linux/fs.h>
/*MDKDEV转换设备号数据类型宏定义*/
#include <linux/kdev_t.h>
/*定义字符设备的结构体*/
#include <linux/cdev.h>
/*分配内存空间函数头文件*/
#include <linux/slab.h>
#include <linux/device.h>
#define DEVICE_NAME "chardevnode"
#define DEVICE_MINOR_NUM 2
#define DEV_MAJOR 0
#define DEV_MINOR 0
#define REGDEV_SIZE 3000
MODULE_LICENSE("Dual BSD/GPL");
/*声明是开源的,没有内核版本限制*/
MODULE_AUTHOR("iTOPEET_dz");
/*声明作者*/
static int numdev_major = DEV_MAJOR ;//主设备号
static int numdev_minor = DEV_MINOR ;//次设备号
module_param(numdev_major,int,S_IRUSR);
module_param(numdev_minor,int,S_IRUSR);
struct reg_dev
{
char *data;
unsigned long size;
struct cdev cdev;
};
struct reg_dev *my_devices;
static struct class * myclass;
/*打开操作*/
static int chardevnode_open(struct inode * inode,struct file * file){
printk(KERN_EMERG "chardevnode_open is success! \n");
return 0;
}
/*关闭操作*/
static int chardevnode_release(struct inode *inode,struct file *file){
printk(KERN_EMERG "chardevnode_release is success! \n");
return 0;
}
/*IO操作*/
static long chardevnode_ioctl (struct file *file, unsigned int cmd, unsigned long arg){
printk(KERN_EMERG "chardevnode_ioctl is success! cmd is %d,arg is %d \n",cmd,arg);
return 0;
}
ssize_t chardevnode_read (struct file *file , char __user *buf, size_t count, loff_t *f_ops){
return 0;
}
ssize_t chardevnode_write (struct file *file , const char __user *buf, size_t count, loff_t *f_ops){
return 0;
}
loff_t chardevnode_llseek (struct file *file , loff_t offset, int ence){
return 0;
}
struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = chardevnode_open,
.release = chardevnode_release,
.unlocked_ioctl = chardevnode_ioctl,
.read = chardevnode_read,
.write = chardevnode_write,
.llseek = chardevnode_llseek,
};
/*设备注册到系统*/
static void reg_init_cdev(struct reg_dev *dev,int index){
int err;
int devno = MKDEV(numdev_major,numdev_minor + index);
/*数据初始化*/
cdev_init(&dev -> cdev,&my_fops);
dev -> cdev.owner = THIS_MODULE;
dev -> cdev.ops = &my_fops;
err = cdev_add(&dev -> cdev,devno,1);
if(err){
printk(KERN_EMERG "failed,cdev_add is %d ,index is %d\n",err,index);
}
else{
printk(KERN_EMERG "cdev_add %d success\n",index);
printk(KERN_EMERG "numdev_minor is %d",numdev_minor);
}
}
static int Ascdev_init(void)
{
int ret = 0;
int i = 0;
printk(KERN_EMERG "numdev_major is %d!\n",numdev_major);
printk(KERN_EMERG "numdev_minor is %d!\n",numdev_minor);
dev_t num_dev;
if(numdev_major){
num_dev = MKDEV(numdev_major,numdev_minor);
//宏命令,用于处理各种设备号相关的数据
//设备注册
ret = register_chrdev_region(num_dev,DEVICE_MINOR_NUM,DEVICE_NAME);
if(ret < 0)
{
printk(KERN_EMERG "register_chrdev_region req is %d is failed \n",num_dev );
}
printk(KERN_EMERG "register_chrdev_region %d is success \n",numdev_major);
}
else{
ret = alloc_chrdev_region(&num_dev,numdev_minor,DEVICE_MINOR_NUM,DEVICE_NAME);
if(ret < 0)
{
printk(KERN_EMERG "alloc_chrdev_region req is %d is failed \n",num_dev );
return -1;
}
numdev_major = MAJOR(num_dev);//huoqu
printk(KERN_EMERG "numdev_major is %d \n",numdev_major);
}
myclass = class_create(THIS_MODULE,DEVICE_NAME);
my_devices = kmalloc(DEVICE_MINOR_NUM * sizeof(struct reg_dev),GFP_KERNEL);
if(!my_devices){
ret = -ENOMEM;
goto fail;
}
memset(my_devices,0,DEVICE_MINOR_NUM * sizeof(struct reg_dev));//初始化缓存为0;
for(i = 0;i < DEVICE_MINOR_NUM;i ++){
my_devices[i].data = kmalloc(REGDEV_SIZE,GFP_KERNEL);
memset(my_devices[i].data,0,REGDEV_SIZE);
reg_init_cdev(&my_devices[i],i);
device_create(myclass,NULL,MKDEV(numdev_major,numdev_minor + i),NULL,DEVICE_NAME"%d",i);//这个 i 可以创建chardevnode0,chardevnode1
}
printk(KERN_EMERG "Ascdev enter!\n");
/*打印信息,KERN_EMERG表示紧急信息*/
return 0;
fail:
unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
printk(KERN_EMERG "kmalloc is fail\n");
return ret;
}
static void Ascdev_exit(void)
{
int i;
for(i = 0;i < DEVICE_MINOR_NUM;i++){
cdev_del(&(my_devices[i].cdev));
device_destroy(myclass,MKDEV(numdev_major,numdev_minor + i));
}
class_destroy(myclass);
// kfree(myclass);
unregister_chrdev_region(MKDEV(numdev_major,numdev_minor),DEVICE_MINOR_NUM);
printk(KERN_EMERG "Ascdev exit!\n");
}
module_init(Ascdev_init);
/*初始化函数*/
module_exit(Ascdev_exit);
/*卸载函数*/
应用:
cpp
/*************************************************************************
> File Name: Invoke.c
> Author:
> Mail:
> Created Time: Fri 27 Sep 2019 10:51:55 PM CST
************************************************************************/
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(void)
{
char * hello_node0 = "/dev/chardevnode0";
char * hello_node1 = "/dev/chardevnode1";
int fd;
if(fd = open(hello_node0,O_RDWR|O_NDELAY) < 0){
printf("hello_node0 open %s is failed\r\n",hello_node0);
}
else{
printf("hello_node0 open %s is success\r\n",hello_node0);
}
close(fd);
if(fd = open(hello_node1,O_RDWR|O_NDELAY) < 0){
printf("hello_node1 open %s is failed\r\n",hello_node1);
}
else{
printf("hello_node1 open %s is success\r\n",hello_node1);
}
close(fd);
return 0;
}
运行结果:
[root@iTOP-4412]# ls
chardevicenode.ko invoke_char_driver
[root@iTOP-4412]# insmod chardevicenode.ko
[ 1951.543724] numdev_major is 0!
[ 1951.545312] numdev_minor is 0!
[ 1951.548335] numdev_major is 248
[ 1951.553133] cdev_add 0 success
[ 1951.554733] numdev_minor is 0
[ 1951.559293] cdev_add 1 success
[ 1951.561050] numdev_minor is 0
[ 1951.565035] Ascdev enter!
[root@iTOP-4412]# ls /sys/class
android_usb gpsdrv kovaplus net scsi_device ump
arvo graphics lcd power_supply scsi_disk usb_device
backlight i2c-adapter lirc ppp scsi_generic video4linux
bdi i2c-dev mali pyra scsi_host
block ieee80211 mdio_bus rc sound
bluetooth input mem rc522 spi_master
chardevnode kone misc regulator switch
firmware koneplus mmc_host rtc tty
[root@iTOP-4412]# ls /dev/chardevnode*
/dev/chardevnode0 /dev/chardevnode1
[root@iTOP-4412]# ./invoke_char_driver
[ 2065.729172] chardevnode_open is success!
[ 2065.732435] chardevnode_open is success!
[ 2065.735821] chardevnode_release is success!
[ 2065.740939] chardevnode_release is success!
hello_node0 open /dev/chardevnode0 is successhello_node1 open /dev/chardevnode1 is success[root@iTOP-4412]#
[root@iTOP-4412]# rmmod chardevicenode
[ 2072.553457] Ascdev exit!