1. 程式人生 > >Linux核心模組驅動之---led驅動

Linux核心模組驅動之---led驅動

/**************************************************************************/ /***************************led.c**********************************************/ #include<linux/module.h>
#include<linux/miscdevice.h>
#include<linux/kernel.h>
#include<linux/init.h>
#include<linux/fs.h>
#include<linux/types.h>
#include<linux/errno.h>
#include<linux/ioctl.h>
#include<linux/cdev.h>
#include<linux/device.h>
#include<linux/ioport.h>
#include<asm/io.h>
#include<asm/uaccess.h>
/*要了解各個標頭檔案中所包含的函式*/
#include"led.h"/*led對應GPIOK虛擬地址*/
unsigned long GPIOK_VA_BASE;
#define GPIOK_CON0_VA GPIOK_VA_BASE
#define GPIOK_CON1_VA GPIOK_VA_BASE+0x4
#define GPIOK_DAT_VA  GPIOK_VA_BASE+0x8
#define GPIO_PUD_VA   GPIOK_VA_BASE+0xc
/*led對應的實體地址*/
#define GPIOK_PA_BASE 0x7f008800
/*linux 採用resource描述掛接在cpu總線上的結構實體*/
struct resource tiny6410_led_resource =

{
.name  = "led io-mem",
.start = GPIOK_PA_BASE,
.end = GPIOK_PA_BASE + 0x10,
.flags = IORESOURCE_MEM,
};
static void tiny6410_led_pin_setup(void)
{
unsigned long start = tiny6410_led_resource.start;
unsigned long size = tiny6410_led_resource.end - tiny6410_led_resource.start;
unsigned long tmp;

/*申請io記憶體*/
request_mem_region(start,size,tiny6410_led_resource.name);

/*對映io記憶體*/

GPIOK_VA_BASE = (unsigned long)ioremap(start,size);//對映的地址 由系統自動分配
printk("對映的虛擬地址 GPIOK_VA_BASE = 0x%lx\n",GPIOK_VA_BASE);

/*對應管教設定為輸出*/
tmp = readl(GPIOK_CON0_VA);
tmp = (tmp & ((0xffffU<<16)|(0x1111U<<16)));
writel(tmp,GPIOK_CON0_VA);

/*對應管腳置高--使led全滅*/
tmp = readl(GPIOK_DAT_VA);//將暫存器在記憶體中的虛擬地址的資料讀出來
tmp |= (0xf<<4);
writel(tmp,GPIOK_DAT_VA);
}
/****************************************************/
static void tiny6410_led_pin_release(void)
{
/**首先要解除對映**/
iounmap((void*)GPIOK_VA_BASE);//引數是 對映到記憶體的地址
release_mem_region(tiny6410_led_resource.start,tiny6410_led_resource.end - tiny6410_led_resource.start);
}
/**************************************************************************************************/
static unsigned long tiny6410_led_getdata(void)
{
return ((readl(GPIOK_DAT_VA)>>4)&0xF);//返回虛擬io記憶體中暫存器的值
}
/*設定led對應的GPIO資料暫存器的值*/
static void tiny6410_led_setdata(int data)
{
unsigned long tmp;
tmp = readl(GPIOK_DAT_VA);
tmp = ~(0xF<<4) | ((data&0xF)<<4);
writel(tmp,GPIOK_DAT_VA);
}
/*****************************************************************************************************/
static long led_ioctl(struct file* filp,unsigned int cmd,unsigned long arg)
{
int ioarg,ret;
/*檢測命令的有效性*/
if(_IOC_TYPE(cmd) != LED_IOC_MAGIC)//檢測命令
return -EINVAL;
if(_IOC_NR(cmd) > LED_IOC_MAXNR)//檢測命令號  如果大於最大的命令號
return -EINVAL;


/*根據命令來執行不同的操作*/

switch(cmd)  {
case LED_IOCGETDATA:{

ioarg = tiny6410_led_getdata();
ret = put_user(ioarg,(int*)arg);
break;
}
case LED_IOCSETDATA:{

ret = get_user(ioarg,(int*) arg);
tiny6410_led_setdata(ioarg);
break;
}
default:
return -EINVAL;
}

return ret;
}
static ssize_t led_read(struct file* filp,char __user* buf,size_t size,loff_t *ppos)
{


}
/********************************************************************************************/
static struct file_operations dev_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = led_ioctl,
.read = led_read,
};
static struct miscdevice misc = 
{
.minor = MISC_DYNAMIC_MINOR,//次裝置號由系統動態分配
.name = DEVICE_NAME,
.fops = &dev_fops,//檔案操作
};
/****************************************************************************************/
static int __init dev_init(void)
{
int ret;


tiny6410_led_pin_setup();//在板子初始化的時候 要將暫存器對映到記憶體中去
ret = misc_register(&misc);

printk("initialized minor =%d\n",misc.minor);

return ret;
}
static void __exit dev_exit(void)
{
tiny6410_led_pin_release();
misc_deregister(&misc);//混雜字元裝置驅動的解除
}
module_init(dev_init);
module_exit(dev_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("kong-hua-sheng");