1、字符设备驱动的API
#include <linux/cdev.h>
#include <linux/slab.h>
1.分配对象
struct cdev {
struct module *owner; //THIS_MODULE
const struct file_operations *ops; //操作方法结构体
struct list_head list; //构成链表
dev_t dev; //设备号
unsigned int count; //设备的个数
} ;
struct cdev cdev;
struct cdev *cdev;
struct cdev *cdev_alloc(void)
//void kfree(const void *addr)
功能:申请内存(sizeof(struct cdev))
参数:
@无
返回值:成功返回结构体指针,失败返回NULL
2.对象的初始化
void cdev_init(struct cdev *cdev, const struct file_operations *fops)
功能:初始化cdev结构体的成员
参数:
@cdev:cdev的结构体指针
@fops:操作方法结构体指针
返回值:无
3.申请设备号
int register_chrdev_region(dev_t from, unsigned count, const char *name)
//void unregister_chrdev_region(dev_t from, unsigned count)
功能:静态指定设备号
参数:
@from:设备号的起始值
@count:设备的个数
@name:设备的名字 cat/proc/devices
返回值:成功返回0,失败返回错误码
int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,const char *name)
//void unregister_chrdev_region(dev_t from, unsigned count)
功能:动态申请设备号
参数:
@dev:申请到的设备号
@baseminor:起始的次设备号
@count:设备的个数
@name:设备的名字 cat/proc/devices
返回值:成功返回0,失败返回错误码
4.注册
int cdev_add(struct cdev *p, dev_t dev, unsigned count)
//void cdev_del(struct cdev *p)
功能:注册
参数:
@p:cdev结构体指针
@dev:设备号
@count:设备的个数
返回值:成功返回0,失败返回错误码
2、字符设备驱动分步实现的流程
mycdev.c
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#define CNAME "mycdev"
struct cdev* cdev;
unsigned int major = 511;
unsigned int minor = 0;
const int count = 3;
struct class* cls;
struct device* dev;
char kbuf[128] = { 0 };
int mycdev_open(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
ssize_t mycdev_read(struct file* file,
char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_to_user(ubuf,kbuf, size);
if (ret) {
printk("copy data to user error\n");
return -EIO;
}
return size;
}
ssize_t mycdev_write(struct file* file,
const char __user* ubuf, size_t size, loff_t* offs)
{
int ret;
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
if (size > sizeof(kbuf))
size = sizeof(kbuf);
ret = copy_from_user(kbuf, ubuf, size);
if (ret) {
printk("copy data form user error\n");
return -EIO;
}
return size;
}
int mycdev_close(struct inode* inode, struct file* file)
{
printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
return 0;
}
const struct file_operations fops = {
.open = mycdev_open,
.read = mycdev_read,
.write = mycdev_write,
.release = mycdev_close,
};
static int __init mycdev_init(void)
{
int ret, i;
dev_t devno;
// 1.分配对象
cdev = cdev_alloc();
if (cdev == NULL) {
printk("cdev alloc memory error\n");
ret = -ENOMEM;
goto ERR1;
}
// 2.初始化对象
cdev_init(cdev, &fops);
// 3.申请设备号
if (major > 0) {
//静态指定
ret = register_chrdev_region(MKDEV(major, minor), count, CNAME);
if (ret) {
printk("static:request device number error\n");
goto ERR2;
}
} else {
//动态申请
ret = alloc_chrdev_region(&devno, 0, count, CNAME);
if (ret) {
printk("dynamic:request device number error\n");
goto ERR2;
}
major = MAJOR(devno);
minor = MINOR(devno);
}
// 4.注册
ret = cdev_add(cdev, MKDEV(major, minor), count);
if (ret) {
printk("register char device driver error\n");
goto ERR3;
}
// 5.自动创建设备节点
cls = class_create(THIS_MODULE, CNAME);
if (IS_ERR(cls)) {
printk("class create error\n");
ret = PTR_ERR(cls);
goto ERR4;
}
for (i = 0; i < count; i++) {
dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mycdev%d", i);
if (IS_ERR(dev)) {
printk("device create error\n");
ret = PTR_ERR(dev);
goto ERR5;
}
}
return 0; /*!!!!!!!!!!!!!!!不要忘记写!!!!!!!!!!!!!!!*/
ERR5:
for (--i; i >= 0; i--) {
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR4:
cdev_del(cdev);
ERR3:
unregister_chrdev_region(MKDEV(major, minor), count);
ERR2:
kfree(cdev);
ERR1:
return ret;
}
static void __exit mycdev_exit(void)
{
int i;
for (i = 0; i < count; i++) {
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
cdev_del(cdev);
unregister_chrdev_region(MKDEV(major, minor), count);
kfree(cdev);
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");
test.c
#include "head.h"
char buf[128] = { 0 };
int main(int argc, const char* argv[])
{
int fd;
if ((fd = open("/dev/mycdev0", O_RDWR)) == -1)
PRINT_ERR("open error");
printf("input > ");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]='\0';
//将终端输入的数据写入到内核空间
write(fd, buf, sizeof(buf));
//将内核中的数据读取出来,打印到终端上
memset(buf,0,sizeof(buf));
read(fd, buf, sizeof(buf));
printf("buf = %s\n",buf);
close(fd);
return 0;
}