Linux驱动(三)——完善设备驱动自动创建设备号

APP部分:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

/*
*argc:应用程序参数个数,包括应用程序本身
*argv[]:具体的参数内容,字符串形式
*./shanwuyanAPP <filename> <r:w> r表示读,w表示写
*/
int main(int argc, char *argv[])
{
	int ret = 0;
	int fd = 0;
	char *filename;
	char readbuf[50];
	char user_data[] = "user data";

	if(argc != 3)
	{
		printf("Error usage!\r\n");
		return -1;
	}
		
	filename = argv[1];	//获取文件名称

	fd = open(filename, O_RDWR);
	if(fd < 0)
	{
		printf("cannot open file %s\r\n", filename);
		return -1;
	}
	/*读操作*/
	if(!strcmp(argv[2], "r"))
	{
		read(fd, readbuf, 50);
		printf("user get data:%s\r\n", readbuf);
	}
	/*写操作*/
	else if(!strcmp(argv[2], "w"))
	{
		write(fd, user_data, 50);
	}
	else
	{
		printf("ERROR usage!\r\n");
	}

	/*关闭操作*/
	ret = close(fd);
	if(ret < 0)
	{
		printf("close file %s failed\r\n", filename);
	}

	return 0;
}

驱动部分:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>

#define SHANWUYAN_NAME "shanwuyan"

struct shanwuyan_dev
{
	struct cdev c_dev;		//字符设备
	dev_t dev_id;			//设备号
	struct class *class;	//类
	struct device *device;	//设备
	int major;				//主设备号
	int minor;				//次设备号
};

struct shanwuyan_dev shanwuyan;	//定义一个设备结构体

/*打开设备*/
static int shanwuyan_open(struct inode *inode, struct file *filp)
{
	printk(KERN_EMERG "shanwuyan_open\r\n");
	return 0;
}

/*释放(关闭)设备*/
static int shanwuyan_release(struct inode *inode, struct file *filp)
{
	printk(KERN_EMERG "shanwuyan_close\r\n");
	return 0;
}

/*读设备*/
static ssize_t shanwuyan_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
{
	char device_data[] = "device data";
	copy_to_user(buf, device_data, sizeof(device_data));	//向用户程序传输设备数据
	return 0;
}

/*写设备*/
static ssize_t shanwuyan_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
{
	char user_data[50];
	copy_from_user(user_data, buf, count);		//获取用户程序写到设备的数据
	printk("device get data:%s\r\n", user_data);
	return 0;
}

static struct file_operations shanwuyan_fops = 
{
	.owner = THIS_MODULE,			//默认
	.open = shanwuyan_open,			//打开设备
	.release = shanwuyan_release,	//关闭设备
	.read = shanwuyan_read,			//读设备
	.write = shanwuyan_write,		//写设备
};

static int __init shanwuyan_init(void)	//驱动入口函数
{
	int ret = 0;
	
	/*1.分配设备号*/
	shanwuyan.major = 0;	//主设备号设置为0,表示用户不给定主设备号,主次设备号都由系统分配
	if(shanwuyan.major)		//如果给定了主设备号,则由系统分配次设备号
	{
		shanwuyan.dev_id = MKDEV(shanwuyan.major, 0);	//把用户给的主设备号和0号次设备号合并成一个设备号
		ret = register_chrdev_region(shanwuyan.dev_id, 1, SHANWUYAN_NAME);	//因为我们只考虑一个设备的情况,所以只分配一个设备号,即设备号0
	}
	else					//如果没有给定主设备号,则主次设备号全部由系统分配
	{
		ret = alloc_chrdev_region(&(shanwuyan.dev_id), 0, 1, SHANWUYAN_NAME);	//只考虑一个设备的情况
		shanwuyan.major = MAJOR(shanwuyan.dev_id);	//获取主设备号
		shanwuyan.minor = MINOR(shanwuyan.dev_id);	//获取次设备号
	}
	if(ret < 0)	//设备号分配失败,则打印错误信息,然后返回
	{
		printk(KERN_EMERG "shanwuyan chrdev_region error!\r\n");
		return -EINVAL;
	}
	else	//如果设备号分配成功,则打印设备的主次设备号
	{
		printk(KERN_EMERG "shanwuyan.major = %d, shanwuyan.minor = %d\r\n", shanwuyan.major, shanwuyan.minor);
	}

	/*2.向内核添加字符设备*/
	shanwuyan.c_dev.owner = THIS_MODULE;
	cdev_init(&(shanwuyan.c_dev), &(shanwuyan_fops));	//初始化字符设备结构体
	cdev_add(&(shanwuyan.c_dev), shanwuyan.dev_id, 1);	//添加设备到内核

	/*3.自动创建设备节点*/
	shanwuyan.class = class_create(THIS_MODULE, SHANWUYAN_NAME);	//创建类
	shanwuyan.device = device_create(shanwuyan.class, NULL, shanwuyan.dev_id, NULL, SHANWUYAN_NAME);

	return 0;
}

static void __exit shanwuyan_exit(void)	//驱动出口函数
{
	/*注销设备号*/
	unregister_chrdev_region(shanwuyan.dev_id, 1);
	/*摧毁设备*/
	device_destroy(shanwuyan.class, shanwuyan.dev_id);
	/*摧毁类*/
	class_destroy(shanwuyan.class);
}

module_init(shanwuyan_init);	//注册入口函数
module_exit(shanwuyan_exit);	//注册出口函数

MODULE_LICENSE("GPL");	//同意GPL开源协议
MODULE_AUTHOR("xxx");	//添加作者名称

Makefile部分:

#!/bin/bash

obj-m += shanwuyan.o

KDIR := /home/topeet/Android/itop4412_kernel_4_14_2_bsp/linux-4.14.2_iTop-4412_scp #这里要对应你的Linux内核目录

PWD ?= $(shell pwd)

all:
	make -C $(KDIR) M=$(PWD) modules

clean:
	make -C $(KDIR) M=$(PWD) clean

5.应用
  编译驱动程序,交叉编译用户程序,拷贝到开发板中。
  在终端输入命令"insmod shanwuyan.ko"加载驱动,可以看到系统分配的主次设备号分别为246和0.
  在这里插入图片描述
在终端输入命令"ls /dev/shanwuyan",可以看到已经自动创建了设备节点"/dev/shanwuyan"。
在这里插入图片描述
在终端输入"./shanwuyanAPP /dev/shanwuyan r",让用户程序读设备,可以看到终端打印出了设备传递给用户程序的信息。
在这里插入图片描述
在终端输入"./shanwuyanAPP /dev/shanwuyan w",让用户程序写设备,可以看到终端打印出了用户程序传递给设备的信息。
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值