红联Linux门户
Linux帮助

初识linux字符驱动

发布时间:2016-11-23 10:32:06来源:linux网站作者:mmmmar
现在对linux设备驱动还没有什么认识,跟着书上敲了一个字符驱动,这里把代码贴一下.
 
测试环境是 Ubuntu 16.04 64bit
 
驱动程序:
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#define CDEVDEMO_MAJOR 0
#define BUFFER_SIZE 512
static int cdevdemo_major = CDEVDEMO_MAJOR;
static char msgbuff[BUFFER_SIZE];
void cdevdemo_exit(void);
int  cdevdemo_init(void);
MODULE_LICENSE("Dual BSD/GPL");
module_param(cdevdemo_major,int,S_IRUGO);
//注册初始化方法
module_init(cdevdemo_init);
//注册退出方法
module_exit(cdevdemo_exit);
struct cdev *my_cdev;
ssize_t cdev_write(struct file *, const char __user *, size_t, loff_t *);
ssize_t cdev_read (struct file *, char __user *, size_t, loff_t *);
intcdev_open (struct inode *,struct file *);
intcdev_release (struct inode *,struct file *);
struct file_operations my_fops = {
.owner = THIS_MODULE,
.open = cdev_open,
.release = cdev_release,
.read = cdev_read,
.write = cdev_write,
};
void init_cdev(void)
{
int ret;
my_cdev = cdev_alloc();
my_cdev->owner = THIS_MODULE;
my_cdev->ops = &my_fops;
//添加字符设备
ret = cdev_add(my_cdev,MKDEV(cdevdemo_major,0),1);
if(ret < 0)
{
printk(KERN_NOTICE "=== cdev_add fail");
}
printk(KERN_NOTICE "=== init_cdev finish");
}
int __init cdevdemo_init(void)
{
int ret;
dev_t devno;
printk(KERN_NOTICE "=== cdevdemo_init 0");
devno = MKDEV(cdevdemo_major,0);
if(cdevdemo_major)
{
printk(KERN_NOTICE "=== cdevdemo_init try register");
ret = register_chrdev_region(devno,1,"cdevdemo");
}else
{
printk(KERN_NOTICE "=== cdevdemo_init auto register");
ret = alloc_chrdev_region(&devno,0,1,"cdevdemo");
cdevdemo_major = MAJOR(devno);
}
if(ret < 0)
{
printk(KERN_NOTICE "=== cdevdemo_init register fail");
return ret;
}
init_cdev();
printk(KERN_NOTICE "=== cdevdemo_init finish");
return 0;
}
void __exit cdevdemo_exit(void)
{
printk (KERN_NOTICE "=== cdevdemo_exit");
//去除字符设备
cdev_del(my_cdev);
unregister_chrdev_region(MKDEV(cdevdemo_major,0),1);
}
ssize_t cdev_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
{
int ret;
printk(KERN_NOTICE "=== cdev_write");
ret = copy_from_user(msgbuff,buf,count%BUFFER_SIZE);
if(ret < 0)
{
printk(KERN_NOTICE "=== cdev_write copy_from_user fail %d",ret);
return -EFAULT;
}
msgbuff[count]   = '-';
msgbuff[count+1] = '-';
msgbuff[count+2] = 'k';
msgbuff[count+3] = 'e';
msgbuff[count+4] = 'r';
msgbuff[count+5] = 'n';
msgbuff[count+6] = 'e';
msgbuff[count+7] = 'l';
msgbuff[count+8] = '\0';
printk(KERN_NOTICE "--- cdev_write : %s",msgbuff);
return count%BUFFER_SIZE;
}
ssize_t cdev_read (struct file *filp, char __user *buf, size_t count, loff_t *offp)
{
int ret;
printk(KERN_NOTICE "=== cdev_read");
ret = copy_to_user(buf,msgbuff,count%BUFFER_SIZE);
if(ret < 0)
{
printk(KERN_NOTICE "=== cdev_read copy_to_user fail %d",ret);
return -EFAULT;
}
printk(KERN_NOTICE "--- cdev_read :%s",msgbuff);
return count%BUFFER_SIZE;
}
intcdev_open (struct inode *inode,struct file *filp)
{
printk(KERN_NOTICE "=== cdev_open");
return 0;
}
intcdev_release (struct inode *inode,struct file *filp)
{
printk(KERN_NOTICE "=== cdev_release");
return 0;
}
 
Makefile
ifneq ($(KERNELRELEASE),)
mymodule-objs := cdev
obj-m := cdev.o  
else
PWD  := $(shell pwd)
KVER ?= $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD)
clean:   
rm -rf *.cmd *.o *.mod.c *.ko .tmp_versions
endif
 
install.sh
#!/bin/bash
module="cdev"
device="cdev"
name="cdevdemo"
insmod $module.ko
if [ $? == 1 ]
then 
exit
fi
major=$(awk "{if(\$2==\"$name\"){print \$1}}"  /proc/devices)
mknod /dev/$device c $major 0
chmod 666 /dev/$device
 
uninstall.sh
#!/bin/bash
module="cdev"
device="cdev"
file="/dev/$device"
if [ -e $file ]
then
rm -rf /dev/$device
echo 'rm device'
fi
echo 'rm module'
/sbin/rmmod $module
 
测试程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int fd,ret;
char buff[100] = "hello I'm from user";
char rbuff[100] = {0};
fd = open("/dev/cdev",O_RDWR,666);
if(fd < 0)
{
puts("open fail");
return -1;
}
ret = write(fd,buff,strlen(buff));
printf("write ret :%d\n",ret);
ret = read(fd,rbuff,100);
printf("read  ret :%d\n%s",ret,rbuff);
return 0;
}
 
运行结果:
write ret :19
read  ret :100
hello I'm from user--kernel
 
本文永久更新地址:http://www.linuxdiyf.com/linux/26248.html