编写mipsel mt7620 Led驱动(四,内核互斥锁)

为什么需要内核互斥锁?

多核处理器下,会存在多个进程处于内核态的情况,而在内核态下,进程是可以访问所有内核数据的,因此要对共享数据进行保护,即互斥处理

 

 

互斥锁主要函数:

//创建互斥锁

DEFINE_MUTEX(mutexname);

或者struct  mutex mutexname;mutex_init(&mutexname);

//加锁,如果加锁不成功,会阻塞当前进程

void mutex_lock(struct mutex *lock);

//解锁

void mutex_unlock(struct mutex *lock);

//尝试加锁,会立即返回,不会阻塞进程

int mutex_trylock(struct mutex *lock);

 

 

#ifndef __RALINK_GPIO_H__
#define __RALINK_GPIO_H__

#include <linux/init.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/poll.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>

#include <asm/mach-ralink/surfboardint.h>
//The Kenel header file, include soc virtual address
#include <asm/mach-ralink/rt_mmap.h>

#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,
    SET_LEN_OF,
    SET_LED_DIR
}SET_LED_CMD;

#endif

 

 

#include "gpio.h"

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

//创建互斥锁
static DEFINE_MUTEX(led_mutex);


/**
* 设置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)
{
    mutex_lock(&led_mutex);//上锁
   
    gpio7140_write_data(gpio,1);

    mutex_unlock(&led_mutex);//解锁
}

/**
* led常灭.
*/
static void set_led_off(unsigned long gpio)
{
    mutex_lock(&led_mutex);//上锁
   
    gpio7140_write_data(gpio,0);

    mutex_unlock(&led_mutex);//解锁
}

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");

posted @ 2014-08-08 18:00  夕相待  阅读(1342)  评论(0)    收藏  举报