Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1315570
  • 博文数量: 213
  • 博客积分: 7590
  • 博客等级: 少将
  • 技术积分: 2185
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-31 17:31
个人简介

热爱开源,热爱linux

文章分类

全部博文(213)

文章存档

2018年(4)

2017年(1)

2015年(1)

2014年(5)

2013年(2)

2012年(2)

2011年(21)

2010年(82)

2009年(72)

2008年(23)

分类: LINUX

2010-07-26 12:23:19


今天将以前学的字符设备一个简单的例子总结下写出来:希望能给初学者一点帮助,该程序是一个很简单的字符驱动程序,应用程序可以访问字符设备的内容:


/***********************************************************************
 *文件名称:cjf_chdev.c
 *简要描述:本程序实现从字符设备被应用程序读取数据的功能
 *当前版本:1.0
 *作者:Ceagle
 ***********************************************************************/

#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ceagle");

#define MAJOR_NUM 250 //定义主设备号为250,如果为0,表示内核动态分配设备号
#define DEVICE_NAME "cjf_chdev" //定义设备号的名称
#define DATA_NUM 20 //写入设备的字符串的最大长度

//声明读数据函数
static int cjf_chdev_read(struct file *filp,char *,size_t,loff_t *);
//声明写数据函数
static int cjf_chdev_write(struct file *filp,char *,size_t,loff_t *);
//定义写入设备的字符串数组
static char cjf_chdev_var[DATA_NUM] ;

static const struct file_operations cjf_chdev_fops =
{
    .read = cjf_chdev_read,
    .write = cjf_chdev_write,
};

static ssize_t cjf_chdev_read(struct file *filp,char *buf,size_t count,loff_t *f_pos)
{ 

    //从内核拷贝数据到用户空间
    if (copy_to_user(buf,&cjf_chdev_var,sizeof(cjf_chdev_var))) {
        return -EFAULT;
    }
    return sizeof(cjf_chdev_var);
}
static ssize_t cjf_chdev_write(struct file *filp,char *buf,size_t count,loff_t *f_pos)
{
    //从用户空间拷贝数据到内核空间


    if (copy_from_user(&cjf_chdev_var,buf,sizeof(cjf_chdev_var))) {
        return -EFAULT;
    }
    return sizeof(cjf_chdev_var);
}

static int __init cjf_chdev_init(void)
{
    int reg;
    //使用函数register_chrdev将主设备号和设备名注册到内核中,
    //如果注册成功,返回0,否则返回负数;
    //如果成功注册动态分配的设备,则返回设备号
    reg = register_chrdev(MAJOR_NUM,DEVICE_NAME,&cjf_chdev_fops);
    if (reg) {
        printk("register fail!\n");
    } else {
        printk("register success!\n");
    }
    return reg;
}

static void __exit cjf_chdev_exit(void)
{
    //使用register_chrdev将设备号和设备名从内核卸载
    unregister_chrdev(MAJOR_NUM,DEVICE_NAME);
    printk("chardev has been unregistered!\n");
}

module_init(cjf_chdev_init);
module_exit(cjf_chdev_exit);

Makefile文件如下:

# Copyleft (C) 2010caojiangfeng<ceaglechina@gmail.com>
#
# /1/Makefile
#
# DATE: 20.05.2010
#
# REV:1.0.A
#
# PLATFROM: Linux/Unix
#
# REV LIST:
# DATE:20.05.2010
# BY: cjf
# MODIFICATION: standard more
#

# target
TARGET= cjf_chdev

# variable
KERNEL= `uname -r`
KDIR= /usr/src/linux-headers-$(KERNEL)
PWD= `pwd`

obj-m:= $(TARGET).o

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

#install
install:
    sudo insmod $(TARGET).ko
uninstall:
    sudo rmmod $(TARGET)
# clean
clean:
     make -C $(KDIR) M=$(PWD) clean
            
#End of Makefile



运行命令make后将cjf_chdev.ko插入内核中如下:
ceagle@ceagle-desktop:~/Code/Kernel/mychardev$ sudo insmod cjf_chdev.ko
ceagle@ceagle-desktop:~/Code/Kernel/mychardev$ lsmod | head -5
Module                  Size  Used by
cjf_chdev                997  0
binfmt_misc             6587  1
vboxnetadp              6326  0
vboxnetflt             15194  0
发现模块已经被插入
或者可以用命令 cat  /proc/devices 查看devices文件看是否插入了模块

ceagle@ceagle-desktop:~/Code/Kernel/mychardev$ cat /proc/devices | grep cjf_chdev
250 cjf_chdev
可以看到主设备号为250的cjf_chdev驱动模块已经被插入了
接着在/dev目录下创建cjf_chdev对应的设备文件
ceagle@ceagle-desktop:~/Code/Kernel/mychardev$ sudo mknod /dev/cjf_chdev c 250 0

下面用一个简单的测试程序test.c测试一下,test.c 如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#define DATA_NUM 20
int main(void)
{
    int fd;
    char *dev = "cjf_chdev";
    char num_write[DATA_NUM],num_read[DATA_NUM];
    memset(num_write,0,sizeof(num_write));
    memset(num_read,0,sizeof(num_read));
    if ((fd = open("/dev/cjf_chdev",O_RDWR)) != -1){
        printf("open device %s success!\n",dev);
        printf("write to %s some data\n",dev);
        scanf ("%s",num_write);
        write(fd,num_write,sizeof(num_write));
        printf("read from %s\n",dev);
        read(fd,num_read,sizeof(num_read));
        printf("%s\n",num_read);
        close(fd);
    } else {
        printf("open device %s faild!\n",dev);
    }
    return 0;
}


编译生成test文件
ceagle@ceagle-desktop:~/Code/Kernel/mychardev$gcc -W -o test test.c
ceagle@ceagle-desktop:~/Code/Kernel/mychardev$sudi ./test
[sudo] password for ceagle:
输入密码后,
open device cjf_chdev success!
write to cjf_chdev some data
hello
read from cjf_chdev
hello
好了,一个简单的字符驱动程序搞定!

更多阅读:
一个简单的字符驱动程序<2>(实现并发控制)
一个简单的字符驱动程序<3>(自旋锁)

一个简单的字符驱动程序<4>(同步控制)
一个简单的字符驱动程序<5>(中断处理)
阅读(1139) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~