之前的字元裝置驅動程式的例子是虛拟的一個記憶體,現在以以一個實際的硬體的設計來為例子
首先LED的程式是一種字元裝置程式
字元裝置方法open和 ioctrl
本文部落格位址:http://blog.csdn.net/b2997215859/article/details/47183419
轉載請注明來源:http://blog.csdn.net/b2997215859/article/details/47183419
然後以下是源代碼
首先是子產品的初始化函數
static intled_init()
{
cdev_init(&cdev,&led_fops);
allo_chrdev_region(&devno, 0 , 1 ,'myled');
cdev_add(&cdev, devno , 1);
return0 ;
}
我們把硬體的初始化後放到open裡來做,open和ioctl均定義在file_operations裡面
static structfile_operations led_fops =
{
.open = led_open ,
.unlocked_ioctl = led_ioctl,
};
注:分好要加上,不然會報錯;并且之間是用逗号隔開,不是用分号
--------------------
然後順手完成對裝置的登出
static voidled_exit()
{
cdev_del(&cdev);
unregister_chrdev_region(&devno,1);
}
第一個語句是對裝置的登出
第二個語句是對裝置号的登出
-------------------
添加#inlcude<linux/cdev.h>來包括cdev等初始化、登出等操作
添加##include<linux/fs.h>來包括struct file_operation等相關東東
-------------------
然後就開始實作裝置函數
首先是open,在open裡實作硬體的初始化,
#define GPBCON 0x56000010 //定義控制寄存器的宏
unsigned int *led_config ; //定義存放GPBCON的虛拟位址
led_config = ioremap(GPBCON , 4); //實體位址轉化為虛拟位址
#define GPBDAT 0x56000014 //定義資料寄存器的宏
unsigned int *led_data; 定義存放GPBDAT的虛拟位址
writel(0x400 , led_config); // l表示寫入32位的值
led_data = ioremap(GPBDAT , 4)//同時将led_data初始化
--------------------
然後是led_ioctl的實作
首先在此之前分析led_ioctl的功能有倆個,關閉和點亮,故建立led.h來定義指令
#define LED_MAGIC 'L' //定義該裝置的幻數
#define LED_ON _IO(LED_MAGIC , 0); //_Io的作用見之前頁面對字元裝置的介紹,led沒有參數傳入,故使用__IO
#define LED_OFF _IO(LED_MAGIC ,1); //第一個參數是裝置的幻數,第二是指令的區分符而已
定義好指令之後,便可以通過switch語句進行判别了
如果是LED_ON,則指派0x00,如果是LED_OFF,則指派0x11
longled_ioctl(struct file *filp, unsigned int cmd , unsigned long arg)
{
switch(cmd)
{
caseLED_ON:
writel(0x00 ,led_data);
return0;
caseLED_OFF:
writel(0xff , led_data);
return0;
default:
return-EINVAL;
}
}
注:關閉led的時候指派是0xff而不是0x11
-----------------------
#include<linux/io.h> //writel的使用
#include "led.h" //包含頭檔案“led.h”
在編譯的時候會出現很多問題,需要細心去調bug<,比如說這次我在led.h的後面的define語句加了分号,然後在led.c的驅動程式中就會報錯,和符号什麼有關,在led.c中報錯233333
然後編寫驅動程式即可
貼出源碼如下
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<sys/ioctl.h>
#include"led.h"
int main(int argc,char *argv[])
{
int fd;
int cmd;
if (argc <2 )
{
printf("please enter the secondpara!\n");
return0;
}
cmd = atoi(argv[1]);
fd = open("/dev/myled",O_RDWR);
if (cmd == 1)
ioctl(fd,LED_ON);
else
ioctl(fd,LED_OFF);
return 0;
}
----------------------------------------------------------------
Led驅動程式的源代碼如下
#include<linux/module.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<linux/fs.h>
#include<linux/io.h>
#include "led.h"
#define GPBCON 0x56000010
#define GPBDAT 0x56000014
unsigned int *led_config ;
unsigned int *led_data;
struct cdev cdev ;
dev_t devno;
int led_open(struct inode *node, struct file *filp)
{
led_config = ioremap(GPBCON,4);
writel(0x400,led_config);//l表示寫入的是32位的值
led_data = ioremap(GPBDAT,4);
return 0;
//mov r1, #0x0
}
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);