Linux核心混雜裝置驅動
阿新 • • 發佈:2019-01-22
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實現一個混雜裝置驅動的程式設計步驟:
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;
}