驱动移植pcDuino的linux移植五gpio驱动开发

文章结束给大家来个程序员笑话:[M]

    调试完pcDuino的led裸板程序,再调pcDuino基于linux内核的gpio驱动开辟,之前的问题水到渠成。本文是在pcDuino的linux移植四简单驱动开辟的基础上,做GPIO驱动开辟。然后写一个应用测试程序,通过敲命令控制pcduino的TX led亮、灭。同时如果你GPIO4、GPIO5接个LED,也会随着亮、灭。

    开辟环境:
系统:ubuntu 10.04.4
单板:pcDuino
编译器:arm-2009q3-67-arm-none-linux-gnueabi-i686-pc-linux-gnu.tar.bz2

    目标:敲命令控制pcDuino上的TX_LED亮、灭

    一、硬件介绍

    仔细看pcDuino上的原理图和pcDuino的手册,发明二者不是完全对应的,还是以原理图为准。根据原理图晓得TX_LED是接到PH15上,可以当作普通IO口用,不需要连跳线

    驱动和移植

    二、编写GPIO驱动代码

    主要包括2部份,驱动代码first_drv.c和应用测试程序firstdrvtest.c以及Makefile。

    驱动代码first_drv.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/gpio.h>
#include <mach/hardware.h>
#include <linux/device.h>

static struct class *firstdrv_class;
static struct class_device *firstdrv_class_dev;

volatile unsigned long *gphcfg1;//0x100 ph9 [6:4]001
volatile unsigned long *gphdat; //0x10c
static int first_drv_open(struct inode *inode, struct file *file)
{
	printk("first_drv_open\n");
	/* 配置GPh9为输出引脚 gpio4*/
	*gphcfg1 |= ((0x1<<4)|(0x1<<8)|(0X1<<28));
	return 0;
}

static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count,loff_t *ppos)
{
	int val;
	printk("first_drv_write\n");
	copy_from_user(&val, buf, count); //	copy_to_user();

	if (val == 1)
	{
		// 点灯
		*gphdat &= ~((0X1<<9)|(0X1<<10)|(1<<15));
	}
	else
	{
		// 灭灯
		*gphdat |= ((0X1<<9)|(0X1<<10)|(1<<15));
	}
	
	return 0;
}

static struct file_operations first_drv_fops ={
	.owner = THIS_MODULE,
	.open  = first_drv_open,
	.write = first_drv_write,
};

int major;
static int first_drv_init(void)
{
	major = register_chrdev(0, "first_drv", &first_drv_fops);
	firstdrv_class = class_create(THIS_MODULE, "firstdrv");
	firstdrv_class_dev = device_create(firstdrv_class,NULL,MKDEV(major, 0), NULL, "xyz");
	gphcfg1 = (volatile unsigned long *)ioremap(0x01c20900, 16);
	gphdat = (volatile unsigned long *)ioremap(0x01c2090c, 16);//gphcfg1 + 3;
	return 0;
}

static void first_drv_exit(void)
{
	unregister_chrdev(major,"first_drv");
	device_unregister(firstdrv_class_dev);
	class_destroy(firstdrv_class);
	iounmap(gphcfg1);
iounmap(gphdat);
}

module_init(first_drv_init);
module_exit(first_drv_exit);

MODULE_LICENSE("GPL");

    文件Makefile:

KERN_DIR = /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0

all:
	make -C $(KERN_DIR) M=`pwd` modules
	
clean:
	make -C $(KERN_DIR) M=`pwd`  modules clean
	rm -rf modules.order

obj-m	+= first_drv.o

    应用测试程序firstdrvtest.c:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

/* firstdrvtest on
  * firstdrvtest off
  */
int main(int argc, char **argv)
{
	int fd;
	int val = 1;
	fd = open("/dev/xyz", O_RDWR);
	if (fd < 0)
	{
		printf("can't open!\n");
	}
	if (argc != 2)
	{
		printf("Usage :\n");
		printf("%s <on|off>\n", argv[0]);
		return 0;
	}

	if (strcmp(argv[1], "on") == 0)
	{
		val  = 1;
	}
	else
	{
		val = 0;
	}
	
	write(fd, &val, 4);
	return 0;
}

    三、编译测试

    每日一道理
人生好似一条河,既有波澜壮阔,汹涌澎湃,也有清风徐来,水波不兴;人生好似一首歌,既有欢乐的音符,也有悲壮的旋律;人生好似一条船,既有一帆风顺时,也有急流险滩处。愿我们都能勇于经受暴风雨的洗礼,接受生活的挑战和考验!

    change@change:~/Si/A10/2_led$ cd ../pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ ls
first_drv.c   first_drv.mod.c  first_drv.o   firstdrvtest.c  modules.order
first_drv.ko  first_drv.mod.o  firstdrvtest  Makefile        Module.symvers
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ make clean
make -C /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0 M=`pwd`  modules clean
make[1]: Entering directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0'
  LD      /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/built-in.o
  CC [M]  /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.o
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_write':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:30: warning: ignoring return value of 'copy_from_user', declared with attribute warn_unused_result
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_init':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:57: warning: assignment from incompatible pointer type
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_exit':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:66: warning: passing argument 1 of 'device_unregister' from incompatible pointer type
include/linux/device.h:692: note: expected 'struct device *' but argument is of type 'struct class_device *'
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.mod.o
  LD [M]  /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.ko
  CLEAN   /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/.tmp_versions
  CLEAN   /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/Module.symvers
make[1]: Leaving directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0'
rm -rf modules.order
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ make
make -C /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0 M=`pwd` modules
make[1]: Entering directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0'
  CC [M]  /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.o
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_write':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:30: warning: ignoring return value of 'copy_from_user', declared with attribute warn_unused_result
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_init':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:57: warning: assignment from incompatible pointer type
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c: In function 'first_drv_exit':
/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.c:66: warning: passing argument 1 of 'device_unregister' from incompatible pointer type
include/linux/device.h:692: note: expected 'struct device *' but argument is of type 'struct class_device *'
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.mod.o
  LD [M]  /home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv/first_drv.ko
make[1]: Leaving directory `/home/change/Si/A10/pcduino/linux-sunxi-sunxi-3.0'
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ ls
first_drv.c   first_drv.mod.c  first_drv.o   firstdrvtest.c  modules.order
first_drv.ko  first_drv.mod.o  firstdrvtest  Makefile        Module.symvers
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$ cp first_drv.ko firstdrvtest /home/change/work/rootfs_dir/fs_mini/home/linux-3.0.62/pcduino/
change@change:~/Si/A10/pcduino/linux-sunxi-sunxi-3.0/drivers/mydrv/led_drv$

    程序比较简单,也太晚了,就不分析了,有问题直接留言吧,开始测试吧。启动前面pcDuino的linux移植一、二、三、四搭建的驱动开辟平台,进入控制台测试

    / # ifconfig eth0 172.16.1.111
<4>wemac wemac.0: WARNING: no IRQ resource flags set.
[   18.250000] wemac wemac.0: WARNING: no IRQ resource flags set.
<6>wemac wemac.0: eth0: link up, 100Mbps, full-duplex, lpa 0x45E1
[   18.400000] wemac wemac.0: eth0: link up, 100Mbps, full-duplex, lpa 0x45E1
/ # ping 172.16.1<7>eth0: no IPv6 routers present
[   28.860000] eth0: no IPv6 routers present

    PING 172.16.1 (172.16.0.1): 56 data bytes
^C
--- 172.16.1 ping statistics ---
4 packets transmitted, 0 packets received, 100% packet loss
/ # ping 172.16.1.137
PING 172.16.1.137 (172.16.1.137): 56 data bytes
64 bytes from 172.16.1.137: seq=0 ttl=64 time=10.015 ms
64 bytes from 172.16.1.137: seq=1 ttl=64 time=1.013 ms
64 bytes from 172.16.1.137: seq=2 ttl=64 time=1.735 ms
64 bytes from 172.16.1.137: seq=3 ttl=64 time=0.814 ms
^C
--- 172.16.1.137 ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 0.814/3.394/10.015 ms
/ # ls
bin      etc      lib      mnt      run      sys      usr
dev      home     linuxrc  proc     sbin     tmp      var
/ # mount -t nfs -o nolock 172.16.1.137:/home/change/work/rootfs_dir/fs_mini /mn
t/
/ # ls /mnt/
bin      etc      lib      mnt      root     sys      usr
dev      home     linuxrc  proc     sbin     tmp
/ # cd /mnt/home/linux-3.0.62/pcduino/
/mnt/home/linux-3.0.62/pcduino # ls
first_drv.ko  firstdrvtest  gpio_drv.ko   gpiodrvtest
/mnt/home/linux-3.0.62/pcduino # insmod first_drv.ko
/mnt/home/linux-3.0.62/pcduino # lsmod
first_drv 1768 0 - Live 0xbf000000
/mnt/home/linux-3.0.62/pcduino # ./firstdrvtest off
first_drv_open
[  303.610000] first_drv_open
first_drv_write
[  303.610000] first_drv_write
/mnt/home/linux-3.0.62/pcduino # ./firstdrvtest on
first_drv_open
[  309.510000] first_drv_open
first_drv_write
[  309.510000] first_drv_write
/mnt/home/linux-3.0.62/pcduino #

    可以看到执行./firstdrvtest off ,pcDuino上的TX LED就灭,执行./firstdrvtest on,pcDuino上的TX LED就亮。测试基本正常,卸载刚刚加载的驱动如下;

    /mnt/home/linux-3.0.62/pcduino # rmmod first_drv
/mnt/home/linux-3.0.62/pcduino # lsmod
/mnt/home/linux-3.0.62/pcduino #

    基本OK了,下一步继续完善驱动。

文章结束给大家分享下程序员的一些笑话语录: 问路
有一个驾驶热气球的人发现他迷路了。他降低了飞行的高度,并认出了地面 上的一个人。他继续下降高度并对着那个人大叫,“打扰一下,你能告诉我我 在哪吗?”
下面那个人说:“是的。你在热气球里啊,盘旋在 30 英尺的空中”。
热气球上的人说:“你一定是在 IT 部门做技术工作”。
“没错”,地面上的人说到,“你是怎么知道的?”
“呵呵”,热气球上的人说,“你告诉我的每件事在技术上都是对的,但对都没 有用”。
地面上的人说,“你一定是管理层的人”。
“没错”,热气球上的人说,“可是你是怎么知道的?”
“呵呵”,地面上的那人说到,“你不知道你在哪里,你也不知道你要去哪,你 总希望我能帮你。你现在和我们刚见面时还在原来那个地方,但现在却是我 错了”。

--------------------------------- 原创文章 By
驱动和移植
---------------------------------

原文地址:https://www.cnblogs.com/xinyuyuanm/p/3098770.html