3-字符设备框架_创建设备文件

2017-02-03  本文已影响0人  ibo
字符设备框架:
struct file_operations *ops = &hello_op    
cdev_init(&cdev,&hello_op)
dev_t *dev = &devno                             
cdev_add(&cdev,devno,1)
用户空间
内核空间
        系统调用
            |
           vfs  (struct cdev   struct file_operations)
            |
          驱动  设备号 = MKDEV(主设备号,次设备号);
//struct cdev cdev;
struct cdev *cdev;
3、初始化file_operations结构体
struct file_operations op = {
    .owner = THIS_MODULE,//代表了当前模块的意思,不写也没错
    .open = hello_open
};
加载函数
卸载函数
规避版权
自动创建设备节点 描述时设备节点就是设备文件
struct class *cls;
cls = class_create(THIS_MODULE,"hello");
这里的hello代表了类的名字,会在/sys/class目录下出现一个文件夹叫做hello,而hello的下面可能出现很多代表子设备的软连接
创建设备文件接口
struct device *devs;
devs = device_create(类结构体指针,父设备的结构体指针,);

struct device *device_create(struct class *class, struct device *parent,dev_t devt, void *drvdata, const char *fmt, ...)
sturct inode
{
    umode_t i_mode 判断设备类型
    struct cdev *i_cdev 存放的是驱动层中cdev结构体的首地址
}
inode结构体是静态的,最初是存放到磁盘上的,第一次打开文件时会被加载到内核中。inode结构体对于一个文件来讲只有一个。


struct file {
    const struct file_operations *f_op; 存放了驱动中的file_operations结构体的首地址
}
用来描述文件的动态信息的,只要打开一次文件就会出现一个新的struct file结构体

int (*open) (struct inode *, struct file *);
驱动层中的open完成的功能:打开文件,申请资源,识别次设备号,存放私有数据
用户空间
内核空间
内核中:
无论应用层还是底层所谓的读写,都是站在应用层的角度来看待的。
读 :
    size_t read(struct file *,char __user *,size_t ,loff_t *)
    {
        将内核空间的数据拷贝到用户空间 copy_to_user();
    }

static inline unsigned long __must_check copy_to_user(void __user *to, const void *from, unsigned long n);

    size_t write(struct file *,const char __user *,size_t ,loff_t *)
    {
        将用户空间的数据拷贝到内核空间 copy_from_user();
    }

    static inline unsigned long __must_check copy_from_user(void *to, const void __user *from, unsigned long n)

应用层:

虚拟地址 = ioremap(物理地址,物理地址占用字节数)

练习 :

Makefile
ifeq ($(KERNELRELEASE),)
#KERNELDIR ?= /lib/modules/$(shell uname -r)/build
KERNELDIR ?= /home/linux/linux-3.14/
PWD ?= $(shell pwd)
modules:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
    cp *.ko /rootfs
app:
    arm-none-linux-gnueabi-gcc test.c -o test
    cp test /rootfs
clean:
    $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
.PHONY: modules clean
else
    obj-m += led.o
endif

head.h
#ifndef     __HEAD_H_
#define     __HEAD_H_

#define     MAGIC   'l'

#define     LED2_ON     _IO(MAGIC,0)
#define     LED2_OFF    _IO(MAGIC,1)
#define     LED3_ON     _IO(MAGIC,2)
#define     LED3_OFF    _IO(MAGIC,3)
#define     LED4_ON     _IO(MAGIC,4)
#define     LED4_OFF    _IO(MAGIC,5)
#define     LED5_ON     _IO(MAGIC,6)
#define     LED5_OFF    _IO(MAGIC,7)
#define     LEDALL_ON   _IO(MAGIC,8)
#define     LEDALL_OFF  _IO(MAGIC,9)

#endif

led.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "head.h"

#define     LED_MAJOR   505
#define     LED_MINOR   0
#define     LED_NUM     1
#define     LED_NAME    "ledx"
#define     CLS_NAME    "led_cls"
#define     DEV_NAME    "led"

#define     GPX2CON     0x11000c40
#define     GPX1CON     0x11000c20
#define     GPF3CON     0x114001e0

volatile unsigned int * gpx2con;
volatile unsigned int * gpx1con;
volatile unsigned int * gpf3con;
volatile unsigned int * gpx2dat;
volatile unsigned int * gpx1dat;
volatile unsigned int * gpf3dat;

dev_t devno;
struct cdev led_cdev;
struct class * cls;
int led_open (struct inode *inode, struct file *file)
{
     printk(" led_open!!!\n");
     return 0;
}
int led_release (struct inode *inode, struct file *file)
{
     printk(" led_release!!!\n");
     return 0;
}
long led_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
{
    printk(" led_ioctl !!!\n");
    switch (cmd)
    {
    case LED2_ON:
        *gpx2dat = (*gpx2dat)|(0x1 << 7);
        *gpx1dat = (*gpx1dat)&~(0x1 << 0);
        *gpf3dat = (*gpf3dat)&~(0x3 << 4);
        break;
    case LED2_OFF:
        *gpx2dat = (*gpx2dat)&~(0x1 << 7);
        *gpx1dat = (*gpx1dat)&~(0x1 << 0);
        *gpf3dat = (*gpf3dat)&~(0x3 << 4);  
        break;
    case LED3_ON:
        *gpx2dat = (*gpx2dat)&~(0x1 << 7);
        *gpx1dat = (*gpx1dat)|(0x1 << 0);
        *gpf3dat = (*gpf3dat)&~(0x3 << 4);  
        break;
    case LED3_OFF:
        *gpx2dat = (*gpx2dat)&~(0x1 << 7);
        *gpx1dat = (*gpx1dat)&~(0x1 << 0);
        *gpf3dat = (*gpf3dat)&~(0x3 << 4);  
        break;
    case LED4_ON:
        *gpx2dat = (*gpx2dat)&~(0x1 << 7);
        *gpx1dat = (*gpx1dat)&~(0x1 << 0);
        *gpf3dat = (*gpf3dat)|(0x1 << 4);
        *gpf3dat = (*gpf3dat)&~(0x1 << 5);  
        break;
    case LED4_OFF:
        *gpx2dat = (*gpx2dat)&~(0x1 << 7);
        *gpx1dat = (*gpx1dat)&~(0x1 << 0);
        *gpf3dat = (*gpf3dat)&~(0x3 << 4);  
        break;
    case LED5_ON:
        *gpx2dat = (*gpx2dat)&~(0x1 << 7);
        *gpx1dat = (*gpx1dat)&~(0x1 << 0);
        *gpf3dat = (*gpf3dat)|(0x1 << 5);
        *gpf3dat = (*gpf3dat)&~(0x1 << 4);  
        break;
    case LED5_OFF:
        *gpx2dat = (*gpx2dat)&~(0x1 << 7);
        *gpx1dat = (*gpx1dat)&~(0x1 << 0);
        *gpf3dat = (*gpf3dat)&~(0x3 << 4);  
        break;
    case LEDALL_ON:
        *gpx2dat = (*gpx2dat)|(0x1 << 7);
        *gpx1dat = (*gpx1dat)|(0x1 << 0);
        *gpf3dat = (*gpf3dat)|(0x3 << 4);  
        break;
    case LEDALL_OFF:
        *gpx2dat = (*gpx2dat)&~(0x1 << 7);
        *gpx1dat = (*gpx1dat)&~(0x1 << 0);
        *gpf3dat = (*gpf3dat)&~(0x3 << 4);  
        break;
    default:
        printk(" fault cmd!!!\n");
        return -EFAULT;
        break;
    }
    return 0;
}
struct file_operations led_fops={
     .owner          = THIS_MODULE,
     .open           = led_open,
     .release        = led_release,
     .unlocked_ioctl = led_ioctl,
};


int __init led_init(void)
{
     int ret;
     printk(" led_init!!!\n");
     devno = MKDEV(LED_MAJOR,LED_MINOR);
     ret = register_chrdev_region(devno,LED_NUM,LED_NAME);
     if (ret < 0)
     {
         printk(" register_chrdev_region fail!!!\n");
         return -EFAULT;
     }
     printk(" register_chrdev_region success!!!\n");
     printk(" major=%d,minor=%d\n",MAJOR(devno),MINOR(devno));

    cdev_init(&led_cdev,&led_fops);
    led_cdev.owner = THIS_MODULE;

    cdev_add(&led_cdev,devno,LED_NUM);

    cls = class_create(THIS_MODULE,CLS_NAME);
    if (IS_ERR(cls))
    {
        printk(" class_create fail!!!\n");
        return -EFAULT;
    }
    device_create(cls,NULL,devno,NULL,DEV_NAME);

    gpx2con = ioremap(GPX2CON,0x4);
    if (NULL == gpx2con)
    {
        printk(" gpx2con ioremap fail!!!\n");
        return -EFAULT;
    }
    gpx1con = ioremap(GPX1CON,0x4);
    if (NULL == gpx1con )
    {
        printk(" gpx1con ioremap fail!!!\n");
        return -EFAULT;
    }
    gpf3con = ioremap(GPF3CON,0x4);
    if (NULL == gpf3con)
    {
        printk(" gpf3con ioremap fail!!!\n");
        return -EFAULT;
    }
    gpx2dat = gpx2con + 1;
    //gpx2dat = ioremap(0x1100c44,0x4);
    gpx1dat = gpx1con + 1;
    gpf3dat = gpf3con + 1;


    *gpx2con = ((*gpx2con)&~(0xf << 28))|(0x1 << 28);
    *gpx1con = ((*gpx1con)&~(0xf <<  0))|(0x1 <<  0);
    *gpf3con = ((*gpf3con)&~(0xff <<16))|(0x11 << 16);

    *gpx2dat =(*gpx2dat)|(0x1 << 7);
    *gpx1dat =(*gpx1dat)|(0x1 << 0);
    *gpf3dat =(*gpf3dat)|(0x3 << 4);



    return 0;
}
module_init(led_init);

void __exit led_exit(void)
{
     printk(" led_exit!!!\n");
     iounmap(gpf3con);
     iounmap(gpx1con);
     iounmap(gpx2con);

     device_destroy(cls,devno);
     class_destroy(cls);

     cdev_del(&led_cdev);
     unregister_chrdev_region(devno,LED_NUM);
}
module_exit(led_exit);

MODULE_LICENSE("GPL");

led.c
#include <stdio.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "head.h"

int main(int argc, char *argv[])
{
    int fd;
    fd = open("/dev/led",O_RDWR);
    if (fd < 0)
    {
        printf(" open fail!!!\n");
        return -1;
    }
    for(;;)
    {
        ioctl(fd,LED2_ON);
        sleep(1);
        ioctl(fd,LED3_ON);
        sleep(1);
        ioctl(fd,LED4_ON);
        sleep(1);
        ioctl(fd,LED5_ON);
        sleep(1);
        ioctl(fd,LEDALL_ON);
        sleep(1);
    }
    close(fd);
    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读