ARM學習筆記之驅動程序篇八----LED設備驅動

一,字符設備控制技術

1.2 設備控制-應用函數

在用戶空間,使用ioctl系統調用來控制設備,原型如下:

int ioctl(int fd,unsigned long cmd)
//fd:要控制的設備文件描述符
//cmd:發送給設備的控制命令
//...:第三個參數是可選的參數,存在與否是依賴於控制命令(第二個參數)

1.3 設備控制-驅動函數

當應用程序使用ioctl系統調用時,驅動程序將由如下函數來響應:

1:2.6.36之前的內核

long (*ioctl)(struct indoe *node,struct file *filp,unsigned int cmd,unsigned long arg)

2:2.6.36之後的內核

long (*unlock_ioctl)(struct file *filp,unsigned int cmd,unsigned long arg)
//參數cmd:通過應用函數ioctl傳遞下來的命令

2.1 控制實現-定義命令

命令從其實質而言就是一個整數,但爲了讓這個整數具備更好的可讀性,我們通常會把這個整數分爲幾個段:類型(8位),序號,參數傳送方向,參數長度。

@type(類型/幻數):表明這是屬於哪個設備的命令。

@number(序號):用來區分同一設備的不同命令。

@direction:參數傳送的方向,可能的值是_IOC_NONE(沒有數據傳輸),_IOC_READ,_IOC_WRITE

@size:參數長度

linux系統提供了下面的宏來幫助定義命令:

@_IO(type,nr):不帶參數的命令

@_IOR(type,nr,datatype):從設備中讀參數的命令

@_IOW(type,nr,datatype):從設備中寫參數的命令

例如:

#define MEM_MAGIC 'm'

#define MEM_SET _IOW(MEM_MAGIC,0,int)

2.2 設備控制-實現操作

unlock_ioctl函數的實現通常就是根據命令執行的一個switch命令。但是,當命令號不能匹配任何一個設備所支持的命令時,返回-EINVAL

switch (cmd){
case a:
case b:
default:
    return -EINVAL;
}

2.3 LED控制代碼實現

//led.h
#define LED_MAGIC 'l'
#define LED_ON _IO(LED_MAGIC,0)
#define LED_OFF _IO(LED_MAGIC,1)

//led.c
#include<linux/module.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/io.h>
#include<mach/gpio-bank-k.h>
#include"led.h"
#define LEDCON 0x7f008800
#define LEDDAT 0x7f008808

unsigned int *led_config;
unsigned int *led_data;

struct cdev cdev;
dev_t devno;

int led_open(struct indoe *node,struct file *filp){
    led_config =ioremap(LEDCON,4);
    writel(0x11110000,led_config);
    led_data=ioremap(LEDDAT,4);
    return 0;	
}

long led_ioctl(struct file *filp,unsigned int cmd,unsigned long arg){
    switch(cmd){
        case LED_ON:
        	writel(0x00,led_data);
        	return 0;
        case LED_OFF:
        	writel(0xff,led_data);
        	return 0;
        default:
        	return -EINVAL;
        		
    }
}

static struct file_operations led_fops={
    .open=led_open,
    .unlocked_ioctl=led_ioctl,
};

static int led_init(){
    cdev_init(&cdev,&led_fops);
    alloc_chrdev_region(&devno,0,1,"myled");
    cdev_add(&cdev,devno,1);
    return 0;	
}

static void led_exit(){
    cdev_del(&cdev);
    unregister_chrdev_region(devno,1);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");

//led_app.c
#include<sys/ioctl.h>
#include"led.h"
int main(int argc,char *argv[]){
    int fd;
    int cmd;
    if(argc<2){
        printf("please enter the second para!\n");
        return 0;
    }
    cmd=atoi(argv[1]);
    fd=open("/dev/myled",O_RDWR);
    if(cmd=1)
        ioctl(fd,LED_ON);
    else
    	ioctl(fd,LED_OFF);
    return 0;
 
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章