分类: 嵌入式
2015-01-02 23:44:10
根据“编写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");