/*
* Status LEDs driver
* Copyright (c) 2012
*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/cdev.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/spinlock.h>
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>
#define DEVICE_NAME "Statusled" //定义设备名
#define LED_MAJOR 261 //定义主设备号
#define LED_MINOR 0
#define LED_MAGIC 0xBB //定义幻数
//定义操作
#define LED_ON _IOW(LED_MAGIC,1,int)
#define LED_OFF _IOW(LED_MAGIC,2,int)
static int led_major = LED_MAJOR; //设置主设备号
struct statusled_dev{ //define dev struct
unsigned char value;
struct semaphore sem; //定义信号量
struct cdev cdev;
};
struct led_gpio {
unsigned base;
unsigned gpio;
#define GPIOF_DIR_OUT 0x00000001
#define GPIOF_DIR_IN 0x00000002
#define GPIOF_INIT_LOW 0x00000004
#define GPIOF_INIT_HIGH 0x00000008
unsigned long flags;
const char *label;
};
static struct led_gpio leds_gpio[]={
{224,6,GPIOF_DIR_OUT | GPIOF_INIT_LOW,"RUN LED"},
{224,8,GPIOF_DIR_OUT | GPIOF_INIT_LOW,"ERRO LED"},
//{},
};
struct statusled_dev *statusled_devp = NULL;
static int leds_open(struct inode *inode, struct file *filp)
{
struct statusled_dev *dev;
int i,j;
dev = container_of(inode->i_cdev, struct statusled_dev, cdev); //通过结构体成员指针找到对应结构体的指针
filp->private_data = dev; //将设备结构体指针赋给文件私有数据指针
//TODO: Status tips
printk("statusled device opened\n");
return 0;
}
static int leds_release(struct inode *inode, struct file *filp)
{
int i,j;
//TODO
printk("statusled device closing\n");
return 0;
}
/*
* leds_write
* I want to modify all the leds status,so,there ervery one ....bits
* note: don't use size.so,the max led number is 8;
*/
static ssize_t leds_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
int i;
struct statusled_dev *dev = filp->private_data;
int num = ARRAY_SIZE(leds_gpio);
down(&dev->sem);
copy_from_user(&(dev->value),buf,1);
for(i=0; i < num; i++){
gpio_set_value(leds_gpio[i].base + leds_gpio[i].gpio,((dev->value >> i) & 0x01)%2);
}
up(&dev->sem);
printk(KERN_ALERT "status LED device write ,dev->value: %d\n",dev->value);
return size;
}
static int leds_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
if(arg > 4){
return -EINVAL;
}
switch (cmd)
{
case LED_ON:
gpio_set_value(leds_gpio[arg].base + leds_gpio[arg].gpio,0);
return 0;
case LED_OFF:
gpio_set_value(leds_gpio[arg].base + leds_gpio[arg].gpio,1);
return 0;
default:
return -EINVAL;
}
}
//file_operations
static struct file_operations leds_fops = {
.owner = THIS_MODULE,
.open = leds_open,
.release = leds_release,
.write = leds_write,
.ioctl = leds_ioctl,
};
static int leds_request(struct led_gpio *leds,size_t num){
int i,ret = 0;
for(i=0;i<num;i++){
ret = gpio_request(leds[i].gpio + leds[i].base,leds[i].label);
if(ret){
printk("%s:request gpio %d faild\n",leds[i].label,leds[i].gpio);
return ret;
}
if((leds[i].flags) & GPIOF_DIR_OUT) {// output
if((leds[i].flags) & GPIOF_INIT_LOW){
gpio_direction_output(leds_gpio[i].base + leds[i].gpio,0);
}
else{
gpio_direction_output(leds_gpio[i].base + leds[i].gpio,1);
}
}
else if((leds[i].flags) & GPIOF_DIR_IN){ //input
gpio_direction_input(leds_gpio[i].base + leds[i].gpio);
}
else{
return -EINVAL;
}
}
return ret;
}
static int leds_free(struct led_gpio *leds,size_t num){
int i,ret = 0;
for(i=0; i<num;i++){
gpio_free(leds[i].base + leds[i].gpio);}
return ret;
}
// inint cdev struct and register a char dev
static void statusled_setup_cdev(struct statusled_dev *dev,int index)
{
int err,devno=MKDEV(led_major, LED_MINOR+index);
cdev_init(&dev->cdev,&leds_fops);
dev->cdev.owner = THIS_MODULE;
dev->cdev.ops = &leds_fops;
err = leds_request(&leds_gpio,ARRAY_SIZE(leds_gpio));
if(err){
printk(KERN_NOTICE "Error:request gpio faild \n");}
err = cdev_add(&dev->cdev,devno,1);
if(err)
printk(KERN_NOTICE "Error %d adding statusled%d\n",err,index);
}
static int __init statusleds_init(void)
{
int result,i,j;
dev_t devno = MKDEV(led_major, LED_MINOR); //创建设备号
//注册设备号
if (led_major) {
result = register_chrdev_region(devno, 1, DEVICE_NAME);
}
else {
result = alloc_chrdev_region(&devno, LED_MINOR, 1, DEVICE_NAME);
led_major = MAJOR(devno);
}
if (result < 0) {
printk("Can't register\n");
return result;
}
statusled_devp = kmalloc(sizeof(struct statusled_dev), GFP_KERNEL);
if (!statusled_devp) {
result = -ENOMEM;
unregister_chrdev_region(devno, 1);
return result;
}
memset(statusled_devp, 0, sizeof(struct statusled_dev));
statusled_setup_cdev(statusled_devp,0);
init_MUTEX(&statusled_devp->sem);
printk("Status LEDs Function is enable\n");
return 0;
}
static void __exit statusleds_exit(void){
int i,j;
leds_free(&leds_gpio,ARRAY_SIZE(leds_gpio));
cdev_del(&statusled_devp->cdev);
kfree(statusled_devp);
unregister_chrdev_region(MKDEV(led_major, LED_MINOR), 1);
printk("Status LEDs Function is disable\n");
}
module_init(statusleds_init);
module_exit(statusleds_exit);
MODULE_AUTHOR("Caijun");
MODULE_DESCRIPTION("Status LEDs Driver"); // 一些描述信息
MODULE_LICENSE("GPL");
1123

被折叠的 条评论
为什么被折叠?



