一,字符設備控制技術
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;
}