1.linux內核混雜設備驅動
1.1混雜設備驅動特點:
本質上還是一類字符設備,在驅動軟件上,混雜設備的主設備號已經由內核指定主設備號爲10;各個混雜設備個體通過次設備號來區分;
1.2linux內核描述混雜設備的數據結構
struct miscdevice{
int minor;
int name;
const struct file_operatiions *fops;
...
};
作用:描述混雜設備
成員:
minor:混雜設備對應的次設備號,切記主設備號
由內核指定爲10,一般指定爲宏MISC_DYNAMIC_MINOR,
表明讓內核來幫你分配一個次設備號
name:設備文件名,並且設備文件由內核自動幫你創建
fops:指向混雜設備的硬件操作方法
1.3實現一個混雜設備驅動的編程步驟:
1.定義初始化混雜設備對象struct miscdevice led_misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = “myled”,
.fops = &led_fops,
};
2.向內核註冊混雜設備對象,一旦註冊完畢,內核就有一個真是的混雜設備驅動
misc_register (&led_misc);
3.從內核卸載混雜設備對象
misc_deregister(&led_misc);
案例:
利用混雜設備編程思想來實現LED驅動
實施步驟:
1.mkdir /opt/drivers/day05/2.0
2.cd /opt/drivers/day05/2.0
3.vim led_drv.c
4.vim led_test.c
5.vim Makefile
6.make
7.arm-linux-gcc -o led_test led_test.c
8.cp led_test led_drv.ko /opt/rootfs
ARM:
1.insmod led_drv.ko
2.ls /dev/myled -lh //查看主,次設備號的信息
3../led_test
#include <linux/init.h>
#include <linux/module.h>
#include <linux/miscdevice.h> //struct miscdevice
#include <linux/fs.h> //strcut file_operations
#include <asm/gpio.h>
#include <plat/gpio-cfg.h>
#include <linux/uaccess.h> //copy_*
//聲明描述LED硬件相關的數據結構
struct led_resource {
int gpio;
char *name;
};
//定義初始化LED硬件信息
static struct led_resource led_info[] = {
[0] = {
.gpio = S5PV210_GPC0(3),
.name = "LED1"
},
[1] = {
.gpio = S5PV210_GPC0(4),
.name = "LED2"
}
};
//定義開關命令字
#define LED_ON 0x100001
#define LED_OFF 0x100002
static long led_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
//定義內核緩衝區,保存用戶要操作燈的編號
int kindex;
//拷貝用戶數據到內核
copy_from_user(&kindex, (int *)arg, sizeof(kindex));
//解析用戶命令,操作硬件
switch(cmd) {
case LED_ON:
gpio_set_value(led_info[kindex - 1].gpio, 1);
break;
case LED_OFF:
gpio_set_value(led_info[kindex - 1].gpio, 0);
break;
}
return 0;
}
//定義初始化硬件操作的方法
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = led_ioctl //發送命令
};
//定義初始化混雜設備對象
static struct miscdevice led_misc = {
.minor = MISC_DYNAMIC_MINOR, //內核分配次設備號
.name = "myled", //設備文件名,內核自動創建/dev/myled
.fops = &led_fops //混雜設備對象具有的硬件操作方法
};
static int led_init(void)
{
int i;
//註冊混雜設備對象到內核
misc_register(&led_misc);
//申請GPIO,配置GPIO爲輸出,輸出0
for (i = 0; i < ARRAY_SIZE(led_info); i++) {
gpio_request(led_info[i].gpio, led_info[i].name);
gpio_direction_output(led_info[i].gpio, 0);
}
return 0;
}
static void led_exit(void)
{
int i;
//輸出0,釋放GPIO資源
for (i = 0; i < ARRAY_SIZE(led_info); i++) {
gpio_set_value(led_info[i].gpio, 0);
gpio_free(led_info[i].gpio);
}
//卸載混雜設備對象
misc_deregister(&led_misc);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define LED_ON 0x100001
#define LED_OFF 0x100002
int main(void)
{
int fd;
int uindex; //用戶緩衝區
//打開設備
//open->....->調用led_open
fd = open("/dev/myled", O_RDWR);
if (fd < 0) {
printf("打開設備失敗!\n");
return -1;
}
//write->...->調用led_write
while (1) {
uindex = 1;
ioctl(fd, LED_ON, &uindex);
sleep(1);
uindex = 2;
ioctl(fd, LED_ON, &uindex);
sleep(1);
uindex = 1;
ioctl(fd, LED_OFF, &uindex);
sleep(1);
uindex = 2;
ioctl(fd, LED_OFF, &uindex);
sleep(1);
}
//關閉設備
//close->...->調用led_close
close(fd);
return 0;
}