Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2985280
  • 博文数量: 685
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 5303
  • 用 户 组: 普通用户
  • 注册时间: 2014-04-19 14:17
个人简介

文章分类

全部博文(685)

文章存档

2015年(116)

2014年(569)

分类: 嵌入式

2014-09-04 17:55:00

原文地址:http://www.cnblogs.com/xuyh/p/3893819.html

根据“编写mipsel mt7620 Led驱动(一)写出简单驱动程序代码”

此LED驱动定义为混杂设备驱动:在Linux驱动中把无法归类的五花八门的设备定义为混杂设备(用miscdevice结构体表述)。

miscdevice共享一个主设备号MISC_MAJOR(即10),但次设备号不同。

所有的miscdevice设备形成了一个链表,对设备访问时内核根据次设备号查找对应的miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。

在内核中用struct miscdevice表示miscdevice设备,然后调用其file_operations结构中注册的文件操作接口进行操作。

 

在Linux内核中,使用struct miscdevice来表示miscdevice。这个结构体的定义为:

struct miscdevice 

{

int minor;

const char *name;

const struct file_operations *fops;

struct list_head list;

struct device *parent;

struct device *this_device;

const char *nodename;

mode_t mode;

};

minor是这个混杂设备的次设备号,若由系统自动配置,则可以设置为MISC_DYNANIC_MINOR,

name是设备名

 

内核中关于file_operations的结构体如下:

struct file_operations {

struct module *owner;

loff_t (*llseek) (struct file *, loff_t, int);

ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);

ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);

ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);

int (*readdir) (struct file *, void *, filldir_t);

unsigned int (*poll) (struct file *, struct poll_table_struct *);

long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);

long (*compat_ioctl) (struct file *, unsigned int, unsigned long);

int (*mmap) (struct file *, struct vm_area_struct *);

int (*open) (struct inode *, struct file *);

int (*flush) (struct file *, fl_owner_t id);

int (*release) (struct inode *, struct file *);

int (*fsync) (struct file *, int datasync);

int (*aio_fsync) (struct kiocb *, int datasync);

int (*fasync) (int, struct file *, int);

int (*lock) (struct file *, int, struct file_lock *);

ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);

unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);

int (*check_flags)(int);

int (*flock) (struct file *, int, struct file_lock *);

ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);

ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);

int (*setlease)(struct file *, long, struct file_lock **);

long (*fallocate)(struct file *file, int mode, loff_t offset,

  loff_t len);

};

对于LED的操作,只需要简单实现io操作就可以了:open, release,unlocked_ioctl

 

 

 

#ifndef __RALINK_GPIO_H__ 
#define __RALINK_GPIO_H__

#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include  
#include

//The Kenel header file, include soc virtual address 
#include

#define RALINK_SYSCTL_ADDR        RALINK_SYSCTL_BASE    // system control 
#define RALINK_REG_GPIOMODE        (RALINK_SYSCTL_ADDR + 0x60) //GPIO MODE

#define RALINK_PRGIO_ADDR        RALINK_PIO_BASE // Programmable I/O

#define  RALINK_REG_PIO7140DATA  (RALINK_PRGIO_ADDR + 0x70)    //数据地址

#define  RALINK_REG_PIO7140DIR     (RALINK_PRGIO_ADDR + 0x74)    //方向地址

typedef  enum  led_stat//ioctl控制cmd 

    SET_LED_ON = 1, //led trun on 
    SET_LEN_OF,       //led trun off 
    SET_LED_DIR      //gpio方向 
}SET_LED_CMD;

#endif

 

 

#include "gpio.h"

#define LED_DRIVER_NAME "led_driver" //设备名字

/** 
* 设置gpio40-gpio71模式为gpio. 
*RGMII2_GPIO_MODE 对应寄存器第10位 
*/ 
static void set_7140_gpio_mode(void) 

    u32 gpiomode; 
    
    gpiomode = le32_to_cpu(*(volatile u32 *)(RALINK_REG_GPIOMODE)); 
    gpiomode |= (0x1<<10); 
    *(volatile u32 *)(RALINK_REG_GPIOMODE) = cpu_to_le32(gpiomode); 
}


/** 
* 设置gpio40-gpio71的数据方向. 
*/ 
static void set_7140_dir(int gpio,int dir) 

    u32 gpiomode; 
    
    gpiomode = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO7140DIR)); 
    gpiomode &= ~(0x01<<(gpio-40)); 
    gpiomode |= (dir?0x01:0x0)<<(gpio-40);

    *(volatile u32 *)(RALINK_REG_PIO7140DIR) = cpu_to_le32(gpiomode);    
}


/** 
* 向gpio40-gpio71脚写数据,0 or 1. 
* 每一位对应一个引脚澹(40---71) 
*/ 
static void gpio7140_write_data(int gpio, int data) 

    unsigned long tmp;

    if(gpio < 40 || gpio > 71) 
        return; 
    
    tmp = le32_to_cpu(*(volatile u32 *)(RALINK_REG_PIO7140DATA)); 
    tmp &= ~(0x01<<(gpio-40));//gpio位置0 
    tmp |= (data?0x01:0x0)<<(gpio-40);//gpio位置data 
    
    *(volatile u32 *)(RALINK_REG_PIO7140DATA) = cpu_to_le32(tmp);

    //printk("write data reg 0x%8x,tmp 0x%8x\n",RALINK_REG_PIO7140DATA,tmp); 
}


/** 
* led常亮. 
*/ 
static void set_led_on(unsigned long gpio) 

    gpio7140_write_data(gpio,1); 
}

/** 
* led常灭. 
*/ 
static void set_led_off(unsigned long gpio) 

    gpio7140_write_data(gpio,0); 
}

long led_driver_ioctl(struct file *filp, unsigned int req, unsigned long arg) 

    unsigned long gpio, data; 
    
    switch(req) { 
        case SET_LED_ON: 
            if(arg < 40 || arg > 71) 
                return -EINVAL; 
            set_led_on(arg); 
            //printk("[driver]led on,gpio %d.\n",(int)arg); 
            break; 
        case SET_LEN_OF: 
            if(arg < 40 || arg > 71) 
                return -EINVAL; 
            set_led_off(arg); 
            //printk("[driver]led off,gpio %d.\n",(int)arg); 
            break; 
        case SET_LED_DIR: 
            gpio = (arg&0xFFFF0000)>>16; 
            data = arg&0x0FFFF; 
            set_7140_dir(gpio, data); 
            break; 
        default: 
            return -EINVAL; 
            break; 
    } 
    return 0; 
}

static int led_driver_open(struct inode *inode, struct file *file) 

    return 0; 
}

static int led_driver_close(struct inode *inode, struct file *file) 

    return 0; 
}

static struct file_operations led_fops = //设备文件描述符 

    .owner        = THIS_MODULE, 
    .open        = led_driver_open, 
    .release    = led_driver_close, 
    .unlocked_ioctl = led_driver_ioctl, 
};

static struct miscdevice led_misc = //杂项设备 

    .minor = MISC_DYNAMIC_MINOR,  //动态设备名字 
    .name = LED_DRIVER_NAME, 
    .fops = &led_fops, 
};


static int __init led_driver_init(void) 

    int ret;

    set_7140_gpio_mode();//set RGMII2_GPIO_MODE to gpio mode.pro.p38 
    
    ret = misc_register(&led_misc); 
    printk("led_driver_init OK!\n"); 
    return ret; 
}

static void __exit led_driver_exit(void) 

    int ret; 
    
    ret = misc_deregister(&led_misc); 
    if(ret < 0) 
        printk("led_driver_exit error.\n"); 
    printk("led_driver_exit.\n"); 
}

module_init(led_driver_init); 
module_exit(led_driver_exit); 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("XYH");


阅读(2064) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~