linux这一个点灯应用程序,ZedBoard上的点灯签名实验(五)自定义IP的Linux驱动和Makefile...

写Linux驱动比写应用程序要难很多,Linux驱动学习是一项浩大的工程,想理清千头万绪,最好的方法就是抓住几个切入点,深入下去,扩展开去。比如用户空间和内核空间的信息交换。用户空间和内核空间的通信是通过文件系统完成的,像procfs, devfs,sysfs等,另一个切入点比如内存管理,像函数malloc, sizeof, free, 甚至memcpy等等。

为我们自己的IP写驱动,基本思路是这样的,把我们的IP看作一个字符设备,当然,我们不一定把它注册为一个chardev, 可以是miscdev, 也可以是platform_device, platform是从Linux 2.6 引入的,很多设备都可以注册为一个platform_device, 想USB,uart,或者AXI 的挂载设备,其基本的思想就是只要知道设备的地址,我就可以和设备通信,只要知道中断,就可以控制设备,至于系统和设备是怎么样链接的,是USB还是uart, 可以忽略,我的理解是,因为他们已经在各自的驱动中考虑了,我们的工作是建筑在前人工作的基础上的。

我把设备注册为一个platform_device, 然后使用procfs和设备进行通信,对于procfs, 如果每次传递的数据超过1页的话,就要用到Seq_file, 我们的IP比较简单,这一点可以不用考虑。首先创建proc_entity, 我们使用函数create_proc_entry, 使用这个函数创建的proc_entity 不能连接自定义的fileoperation, 而只能使用默认的,也就是proc_entity结构体的2个成员,write_proc 和 read_proc, 实际上我们只需要实现write_proc就可以了。新建一个文档myled.c, 我的代码如下,

#include

#include

#include /* Needed for copy_from_user */

#include /* Needed for IO Read/Write Functions */

#include

#include /* Needed for Proc File System Functions */

#include /* Needed for Sequence File Operations */

#include /* Needed for Platform Driver Functions */

/* Define Driver Name */

#define DRIVER_NAME "myled"

unsigned long *base_addr; /* Vitual Base Address */

struct resource *res; /* Device Resource Structure */

unsigned long remap_size; /* Device Memory Size */

struct proc_dir_entry *myled_proc_entry;

static struct platform_device myled = {

.name = DRIVER_NAME,

.id = -1,

};

static int myproc_read(char *page, char **start, off_t off, int count, int *eof, void *data)

{

return 0;

}

static ssize_t myproc_write(struct file *file, const char __user *buffer,

unsigned long count, void *data)

{

unsigned long count2 = count;

u32 myled_value;

char mychar[32];

if(count2 >= sizeof(mychar))

count2 = sizeof(mychar) - 1;

if(copy_from_user(mychar,buffer,count2))

return -EFAULT;

mychar[count2]='\0';

myled_value = simple_strtoul(mychar,NULL,0);

wmb();

iowrite32(myled_value,base_addr);

return count;

};

static int __devinit myproc_probe(struct platform_device *pdev)

{

myled_proc_entry = create_proc_entry(DRIVER_NAME,0,NULL);

if(myled_proc_entry == NULL) {

printk("Couldn't create proc entry\n");

}

base_addr = ioremap(0x7E400000, 1);

if(base_addr == NULL) {

printk("Couldn't create proc entry\n");

}

myled_proc_entry->write_proc = myproc_write;

myled_proc_entry->read_proc = myproc_read;

return 0;

};

static struct platform_driver myled_driver = {

.probe = myproc_probe,

.driver = {

.name = DRIVER_NAME,

.owner = THIS_MODULE,

},

};

static int __init myled_init(void)

{

platform_device_register(&myled);

platform_driver_register(&myled_driver);

// myled_proc_entry->write_proc = myproc_write;

return 0;

};

static void __exit myled_exit(void)

{

remove_proc_entry(DRIVER_NAME,NULL);

iounmap(base_addr);

release_mem_region(0x7E400000, 1);

platform_driver_unregister(&myled_driver);

}

module_init(myled_init);

module_exit(myled_exit);

MODULE_AUTHOR("Fahui, Gong");

MODULE_LICENSE("GPL");

MODULE_DESCRIPTION(DRIVER_NAME ": myled driver");

MODULE_ALIAS(DRIVER_NAME);

我的代码可能看起不太完美,但点亮LED足够了。驱动完成以后可以编辑一个简单的Makefile, 在myled.c相同的目录下命令 gedit Makefile, 代码如下,

obj-m := myled.o

all:

make -C ../linux-digilent-3.6-digilent-13.01/ M=$(PWD) modules

clean:

make -C ../linux-digilent-3.6-digilent-13.01/ M=$(PWD) clean

Makefile的作用是告诉编译器,怎么样去编译,这儿我们在Makefile中没有声明编译器,所以要编译的话,要在myled.c 和 Makefile的目录下执行命令make ARCH=arm CROSS_COMPILE=arm-xilinx-linux-gnueabi- 编译完成后在相同目录下得到文件myled.ko,把这个文件拷到 ZedBoard SD卡的 ZED_BOOT分区上。执行如图命令,可见驱动myled加载正确。

编辑makefile的时候要注意一个窍门,all 和 clean 下边的2行一定要对齐,否则会出错。可以先把光标定位到行头,然后摁一下TAB键。

aa71320cd65f70766a1233b7702365bd.png

加载驱动功后,就可以编个应用程序试试了, Digilent提供了一个LED闪烁的程序,我们可以测试一下,新建一个C文件,输入代码如下,

#include

#include

#include

void main(void)

{

FILE* fp;

while(1) {

fp = fopen("/proc/myled", "w");

if(fp == NULL) {

printf("Cannot open /proc/myled for write\n");

return -1;

}

fputs("0x0F\n", fp);

fclose(fp);

sleep(1);

fp = fopen("/proc/myled", "w");

if(fp == NULL) {

printf("Cannot open /proc/myled for write\n");

return -1;

}

fputs("0x00\n", fp);

fclose(fp);

sleep(1);

}

return 0;

}

然后,在相同的目录下新建Makefile, 输入代码,

CC = arm-xilinx-linux-gnueabi-gcc

CFLAGS = -g

all : led_blink

led_blink : led_blink.o

${CC} ${CFLAGS} –o $^ $@

clean :

rm –rfv *.o

rm –rfv led_blink

.PHONY : clean

在这个Makefile 中我们声明了交叉编译器,所以编译的时候只需在应用程序和makefile相同目录下执行make. 就可以得到和应用程序相同文件名的可执行文件,把他拷到SD卡的ZED_BOOT分区。在终端中输入如下图的命令。

1823e29fb31f655a8d9c97216ef8be98.png

运行结果,发不了视频,只能截图了。

127b93038d6dfcbd4511f3958e0af018.png

ca0e38cd37aa7c1e3b68f69ccbf83685.png

a72ff9fa25ac7f31bcb8653d3b4dc8ab.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值