首页 » 曾经 » 过时技术文章 » 正文

linux字符型设备(chrdev)驱动初步分析

2117.03.06备注:在恢复文章时代码的格式丢失,请匆阅读此文,以免误导.

本文简略地分析总结了一下linux的字符型设备驱动编写流程,以满足一些简单的驱动编写,如驱动硬件IO等操作.
除了要包含的那一堆头文件外,linux的字符型驱动主要程序实际上只有两个接口:

module_initmydev_init;
module_exitmydev_exit;

module_init与module_ext分别用来指明内核在初始化与卸载驱动时所指向的函数入口. 在指明了函数入口后,就须要编写这两个函数的具估内容了.

首先:拿mydev_init来说:

static int __init mydev_initvoid;

int ret;
some_codes;
ret=register_chrdevXXX_MAJOR,DEVICE_NAME,&XXX_fops;
some_codes;

其中mydev_init的函数格式为固定的static int __init mydev_init(void);

整个函数里最重要的一步当然是ret=register_chrdev(XXX_MAJOR,DEVICE_NAME,&XXX_fops);

作 用是向内核注册一个字符型设备驱动,其中第一个参数为主设备号(如果为0表示由系统分配),第二个为驱动名称(将会在/dev目录下升成这个文件),第三 个参数为file_operations结构函数地址.我们要做的工作就是去完成file_operations这个结构体里的各个成员,它们完成与应用 程序的沟通.

在file_operations结构体中有非常多的成员,我们只须要完成我们关心的部份即可,不须要完全是实现它.以下是一个适用于s3c2440控制IO的一个演示示例,这里我们假定GPG4上接有一个LED,我们的目的就是驱动它的亮灭:

1.创建文件csmekdev.c放到内核源码目录/drivers/char.内容如下

#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/regs-clock.h>
#include <plat/regs-timer.h>

#include <mach/regs-gpio.h>
#include <linux/cdev.h>

#include <linux/fs.h>

#define DEVICE_NAME "csmekdev" //设备名csmekdev
#define CSMEKDEV_MAJOR 220     //主设备号220

static int csmekdev_ioctlstruct inode *inode, struct file *file,
    unsigned int cmd, unsigned long arg

                          s3c2410_gpio_setpinS3C2410_GPG4,
    cmd;

static ssize_t dev_writestruct file *file, const char *buffer, size_t count, loff_t *ppos

    unsigned char stats;
int ret;
if
    count == 0 return count;

ret = copy_from_user & stats, buffer, sizeof stats ? -EFAULT : 0;
if
    ret return ret;

stats &= 0x01;
s3c2410_gpio_setpinS3C2410_GPG4, stats;

return count;

static struct file_operations csmekdev_fops =
                                  .owner = THIS_MODULE,
                              .ioctl = csmekdev_ioctl,
                              .write = dev_write,
                              ;

static int __init csmekdev_module_initvoid

    int ret;
int i;
ret = register_chrdevCSMEKDEV_MAJOR, DEVICE_NAME, &csmekdev_fops;
if
    ret < 0 printkDEVICE_NAME " can't register major number\n";
return ret;

s3c2410_gpio_cfgpinS3C2410_GPG4, S3C2410_GPIO_OUTPUT;
/*  s3c2410_gpio_setpin(S3C2410_GPG4, 0);    */
printkDEVICE_NAME " initialized\n";
return 0;

static void __exit csmekdev_module_exitvoid

    unregister_chrdevCSMEKDEV_MAJOR,
    DEVICE_NAME;
printkDEVICE_NAME " removed\n";

module_initcsmekdev_module_init;
module_exitcsmekdev_module_exit;

2.然后修改Kconfig在文件最后加入

config CSMEKDEV_SMDK2440
tristate "CsmekDev on SMDK2440"
“`
[MEDIUM]3.再修改makefile加入:[/MEDIUM]

“obj-$(CONFIG_CSMEKDEV_SMDK2440) += csmekdev.o”

然后menuconfig时,在 Device Drivers->Character devices中,将CsmekDev on SMDK2440编译进内核(即选择为* 不能是选择为M).然后编译,烧录.在开发板上运行”cat /proc/devices”可以看到我们的驱动已经注册到内核,如下图:

http–csmek.com-images-article-201110-proc

然后我们建立设备文件:”mknod /dev/csmekdev c 220 0″.

这 样就会在/dev目录下建立一个csmekdev的文件.我们对这个文件的操作就可完成一些动作比如: “echo 0 > /dev/csmekdev” 即GPG4置低,”echo 1 > /dev/csmekdev”置高GPIO,也可以使用IOCTL的方式,只需要我们去完善csmekdev_fops结构体成员.

发表评论