威海泰浩建设集团有限公司网站,青岛城运控股集团,wordpress加密修改,网络卖货怎么卖现在#xff0c;我们来编写自己第一个字符设备驱动 —— 点亮LED。#xff08;不完善#xff0c;后面再完善#xff09; 硬件平台#xff1a;Exynos4412#xff08;FS4412#xff09; 编写驱动分下面几步#xff1a; a -- 查看原理图、数据手册#xff0c;了解设备的操… 现在我们来编写自己第一个字符设备驱动 —— 点亮LED。不完善后面再完善 硬件平台Exynos4412FS4412 编写驱动分下面几步 a -- 查看原理图、数据手册了解设备的操作方法 b -- 在内核中找到相近的驱动程序以它为模板进行开发有时候需要从零开始 c -- 实现驱动程序的初始化比如向内核注册这个驱动程序这样应用程序传入文件名内核才能找到相应的驱动程序 d -- 设计所要实现的操作比如 open、close、read、write 等函数 e -- 实现中断服务中断不是每个设备驱动所必须的 f -- 编译该驱动程序到内核中或者用 insmod 命令加载 g-- 测试驱动程序 下面是一个点亮LED 的驱动 第一步当然是查看手册查看原理图找到相应寄存器 查看手册四个LED 所用寄存器为 led2 GPX2CON 0x11000c40 GPX2DAT 0x11000c44 led3 GPX1CON 0x11000c20 GPX1DAT 0x11000c24 led4 3-4 3-5 GPF3CON 0x114001e0 GPF3DAT 0x114001e4 这里要注意arm体系架构是io内存必须要映射 ioremap( ); 其作用是物理内存向虚拟内存的映射。 用到 writel readl这两个函数详细解释会在后面不上先看一下简单用法 以LED2为例下面是地址映射及读写 [cpp] view plaincopy int *pgpx2con ; int *pgpx2dat; pgpx2con ioremap( GPX2CON, 4); pgpx2dat ioremap(GPX2DAT,4); readl(pgpx2con); writel(0x01, pgpx2dat ); 下面是驱动程序后面会更完善 [cpp] view plaincopy #include linux/module.h #include linux/fs.h #include linux/cdev.h #include linux/device.h #include asm/io.h #include asm/uaccess.h static int major 250; static int minor0; static dev_t devno; static struct class *cls; static struct device *test_device; #define GPX2CON 0x11000c40 #define GPX2DAT 0x11000c44 #define GPX1CON 0x11000c20 #define GPX1DAT 0x11000c24 #define GPF3CON 0x114001e0 #define GPF3DAT 0x114001e4 static int *pgpx2con ; static int *pgpx2dat; static int *pgpx1con ; static int *pgpx1dat; static int *pgpf3con ; static int *pgpf3dat; void fs4412_led_off(int num); void fs4412_led_on(int num) { switch(num) { case 1: writel(readl(pgpx2dat) |(0x17), pgpx2dat); break; case 2: writel(readl(pgpx1dat) |(0x10), pgpx1dat); break; case 3: writel(readl(pgpf3dat) |(0x14), pgpf3dat); break; case 4: writel(readl(pgpf3dat) |(0x15), pgpf3dat); break; default: fs4412_led_off(1); fs4412_led_off(2); fs4412_led_off(3); fs4412_led_off(4); break; } } void fs4412_led_off(int num) { switch(num) { case 1: writel(readl(pgpx2dat) (~(0x17)), pgpx2dat); break; case 2: writel(readl(pgpx1dat)(~(0x10)), pgpx1dat); break; case 3: writel(readl(pgpf3dat) (~(0x14)), pgpf3dat); break; case 4: writel(readl(pgpf3dat) (~(0x15)), pgpf3dat); break; } } static int led_open (struct inode *inode, struct file *filep) {//open fs4412_led_off(1); fs4412_led_off(2); fs4412_led_off(3); fs4412_led_off(4); return 0; } static int led_release(struct inode *inode, struct file *filep) {//close fs4412_led_off(1); fs4412_led_off(2); fs4412_led_off(3); fs4412_led_off(4); return 0; } static ssize_t led_read(struct file *filep, char __user *buf, size_t len, loff_t *pos) { return 0; } static ssize_t led_write(struct file *filep, const char __user *buf, size_t len, loff_t *pos) { int led_num; if(len !4) { return -EINVAL; } if(copy_from_user(led_num,buf,len)) { return -EFAULT; } fs4412_led_on(led_num); printk(led_num %d \n,led_num); return 0; } static struct file_operations hello_ops { .open led_open, .release led_release, .read led_read, .write led_write, }; static void fs4412_led_init(void) { pgpx2con ioremap(GPX2CON,4); pgpx2dat ioremap(GPX2DAT,4); pgpx1con ioremap(GPX1CON,4); pgpx1dat ioremap(GPX1DAT,4); pgpf3con ioremap(GPF3CON,4); pgpf3dat ioremap(GPF3DAT,4); writel((readl(pgpx2con) ~(0xf28)) |(0x128),pgpx2con) ; writel((readl(pgpx1con) ~(0xf0)) |(0x10),pgpx1con) ; writel((readl(pgpf3con) ~(0xff16)) |(0x1116),pgpf3con) ; } static int led_init(void) { int ret; devno MKDEV(major,minor); ret register_chrdev(major,led,hello_ops); cls class_create(THIS_MODULE, myclass); if(IS_ERR(cls)) { unregister_chrdev(major,led); return -EBUSY; } test_device device_create(cls,NULL,devno,NULL,led);//mknod /dev/hello if(IS_ERR(test_device)) { class_destroy(cls); unregister_chrdev(major,led); return -EBUSY; } fs4412_led_init(); return 0; } void fs4412_led_unmap(void) { iounmap(pgpx2con); iounmap(pgpx2dat ); iounmap(pgpx1con); iounmap(pgpx1dat ); iounmap(pgpf3con ); iounmap(pgpf3dat ); } static void led_exit(void) { fs4412_led_unmap(); device_destroy(cls,devno); class_destroy(cls); unregister_chrdev(major,led); printk(led_exit \n); } MODULE_LICENSE(GPL); module_init(led_init); module_exit(led_exit); 测试程序 [cpp] view plaincopy #include sys/types.h #include sys/stat.h #include fcntl.h #include stdio.h main() { int fd,i,lednum; fd open(/dev/led,O_RDWR); if(fd0) { perror(open fail \n); return ; } for(i0;i100;i) { lednum0; write(fd,lednum,sizeof(int)); lednum i%41; write(fd,lednum,sizeof(int)); sleep(1); } close(fd); } makefile: [cpp] view plaincopy ifneq ($(KERNELRELEASE),) obj-m:hello.o $(info 2nd) else #KDIR : /lib/modules/$(shell uname -r)/build KDIR : /home/xiaoming/linux-3.14-fs4412 PWD:$(shell pwd) all: $(info 1st) make -C $(KDIR) M$(PWD) modules arm-none-linux-gnueabi-gcc test.c sudo cp hello.ko a.out /rootfs/test/ clean: rm -f *.ko *.o *.symvers *.mod.c *.mod.o *.order endif 编译结束后将a.out 和 hello.ko 拷贝到开发板中 # insmod hello.ko #mknod /dev/hello c 250 0 #./a.out 会看到跑马灯效果。 后面会对该驱动完善。