准备工作(Led驱动):
1 准备测试的工具
2 准备相关字符设备驱动的知识
3 准备相关驱动(LED)文件
4 准备相关的硬件知识,获取硬件开发人员提供的LED接口。
driver/char
ps
led_player 701
kill 701
./ledtest 0 0
./ledtest 0 1
./ledtest 0 2
./ledtest 0 3
./ledtest 1 0
./ledtest 1 1
./ledtest 1 2
./ledtest 1 3
./dxctest 0 0
./dxctest 0 1
led0~led3, GPB5~GPB8
LED开发驱动的步骤:
1 开发myled.c文件存放在虚拟机中的linux-2.6-32.2/drivers/char下
2 在char目录下,修改Makefile,把我的源代码加入我们的编译里面来。
3 在char目录下,修改Kconfig,首先定义为内核模块准备调试驱动
4.1 make menuconfig( 要先在Linux-2.6-32.2中 cp config_mini2440_n35 .config)
4.2 重新编译内核make zImage, 生成zImage文件(注意:要先配好arm-linux-gcc的环境变量-> exprot PATH=$PATH:/usr/local/arm/4.3.2/bin)。
5 在超级终端和dwn软件中,下载zImage开发板
6.1 make modules,产生myled.ko的内核模块。
6.2 通过超级终端,用rz命令下载myled.ko文件到开发板。
7 insmod myled.ko(在超级终端)加载内核模块
8 more /proc/devices查看我们驱动是不是被系统认识
9 如果系统认识驱动,会看到主设备号(默认253),敲“空格”向下移动,就可以看到,记录下来
10 cd /dev
11 mknod myled c 253 0 (c为字符设备,253是主设备号,0是 次设备号)
12 ls led
13 cd /
14 ps
15 kill 701
rz(从电脑传输驱动测试文件testled到开发板)
chmod 777 testled
16 ./testled 0 0(0 0可以是0,1的任何组合)
(12 make menuconfig,把M改为*,make zImage)
写代码:
1 内核模块的要素完成
2 初始化函数,确认主设备号,次设备号。
3 初始化函数,分配内存
4 初始化函数,安装cdev
5 实现file操作函数
obj-$(CONFIG_MYLED_MINI2440) += myled.o
int main()
fp = open("/dev/dfsgdsg", 0)
ioctl(fp, atoi(argv[1]), atoi(argv[2]));
return;
arm-linux-gcc 54te.c -o dxctest
具体操作:
1 做测试工具arm-linux-gcc编译 ---testled
open,close,ioctl
2 把内核模块的代码拷贝过来,做一定的修改。
3 初始化函数增加主次设备号申请的代码
led_major,led_minor,dev
4 初始化函数增加申请内存空间的代码
(cdev *)led_device
5 初始化函数增加字符设备初始化代码
cdev_init cdev_add
led_device led_fops
6 exit函数代码完成
7 增加led_fops定义
8 实现led_fops所定义的函数接口
open,release,ioctl
9 拷贝所有.h文件
10 修改Makefile
CONFIG_XXX myled.o
11 修改Kconfig
config XXX
12 make menuconfig 选中我们的配置项为M
13 make zImage ---zImage
14 make modules ---myled.ko
15 开发板环境完成(dnw里USB OK)
16 下载zImage
more /proc/version检查一下
17 通过rz命令下载testled,myled.ko
18 chmod 777 testled
19 ps查看led-player进程号(701)
20 kill 701杀死进程(灯停住不动,状态固定)
21 insmod ./myled.ko
22 more /proc/devices确认主设备号(253)
23 cd /dev
mknod (myled 测试工具) c 主 次
24 ./testled 0 0(0,1 1,0 1,1)
现象:单独控制
led驱动代码:(myled_driver.c)
#include <linux/module.h>
#include <linux/autoconf.h>
#include <linux/init.h>
#include <linux/kernel.h> /* printk() */
#include <linux/slab.h> /* kmalloc() */
#include <linux/fs.h> /* everything... */
#include <linux/errno.h> /* error codes */
#include <linux/types.h> /* size_t */
#include <linux/fcntl.h> /* O_ACCMODE */
#include <linux/cdev.h> /* cdev...*/
#include <asm/io.h> /* writel(),readl()... */
#include <asm/system.h> /* cli(), *_flags */
#include <asm/uaccess.h> /* copy_*_user */
#include <linux/wait.h> /* wake_up_interruptible()... */
#include <linux/delay.h> /* udelay() */
#include <linux/miscdevice.h>
#include <asm/irq.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/mm.h>
#include <linux/moduleparam.h>
#include <linux/ioctl.h>
#include <linux/string.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/gpio.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#define DEVICE_NAME "myled" //宏定义设备名称
static int led_major = 0; //初始化主设备号
static int led_minor = 0; //初始化次设备号
struct cdev *led_device; //定义cdev结构体指针
//下面的两个数组是处理器相关的信息
static unsigned long led_table [] = {
S3C2410_GPB(5),
S3C2410_GPB(6),
S3C2410_GPB(7),
S3C2410_GPB(8),
};
static unsigned int led_cfg_table [] = {
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
};
//设备打开函数
static int myled_open(struct inode *inode, struct file *filp)
{
int i;
for (i = 0; i < 4; i++) {
s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);
s3c2410_gpio_setpin(led_table[i], 0);
}
return 0;
}
//设备关闭函数
static int myled_release(struct inode *inode, struct file *filp)
{
return 0;
}
//设备操作函数
static int myled_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case 0:
case 1:
if (arg > 4) {
return -EINVAL;
}
s3c2410_gpio_setpin(led_table[arg], !cmd);
return 0;
default:
return -EINVAL;
}
}
struct file_operations led_fops = //字符驱动和内核的接口:file_operations结构体
{ //字符驱动只要实现一个file_operations结构体,并注册到内核中,内核就有了操作此设备的能力。
.owner = THIS_MODULE, //指向模块自身。
.open = myled_open, //打开设备
.release = myled_release, //关闭设备
.ioctl = myled_ioctl, //操作设备
};
static void __exit my_led_exit(void) //模块结束函数
{
//MKDEV是因为要重新通过主次设备号合成一个设备号,后面注销时用,
//以前在模块入口函数里的设备号已经不能用了,函数不同了,而led_major, led_minor是全局变量
dev_t devno = MKDEV(led_major, led_minor); //通过主次设备号获得设备号
if (led_device){
/* Get rid of our char dev entries */
cdev_del(led_device); //删除设备
kfree(led_device); //释放内存
led_device = NULL;
}
/* cleanup_module is never called if registering failed */
unregister_chrdev_region(devno, 1); //取消注册设备号
return;
}
static int __init my_led_init(void) //模块入口函数
{
int result = 0;
dev_t dev = 0; //初始化设备号
result = alloc_chrdev_region(&dev, led_minor, 1, DEVICE_NAME);/*自动分配设备号
参数分别是获取的设备号(输出参数),第一个次设备号,次设备号数量,设备名称 */
led_major = MAJOR(dev); //通过设备号提取主设备号
if (result < 0) {
printk(KERN_WARNING "wfet_kb: can't get major %d\n", led_major);
return result;
}
led_device = kmalloc(sizeof(struct cdev), GFP_KERNEL); //为设备分配内存
if (!led_device) {
result = -ENOMEM;
unregister_chrdev_region(dev, 1);
return result;
}
memset(led_device, 0, sizeof(struct cdev)); //清空内存
cdev_init(led_device, &led_fops); //字符设备初始化函数:把为设备分配的内存与操作设备的结构相关联
led_device->owner = THIS_MODULE;
result = cdev_add (led_device, dev, 1); //设备增加
if (result) {
printk(KERN_NOTICE "Error %d adding LED device, major_%d", result, MAJOR(dev));
kfree(led_device);
unregister_chrdev_region(dev, 1);
return result;
}
return 0;
}
module_init(my_led_init); //模块入口函数
module_exit(my_led_exit); //模块出口函数
MODULE_LICENSE("GPL");
测试的应用程序(testled.c):
#include<stdio.h>
int main(int argc,char *argv[])
{
int fp;
if(argc<2)
{
printf("argc error\n");
return 0;
}
fp=open("/dev/myled",0);
if(fp<0)
{
printf("Open error\n");
return 0;
}
printf("test:%d\n",atoi(argv[1]));
if(atoi(argv[1])<8)
{
ioctl(fp,(atoi(argv[1])-atoi(argv[1])/2),(atoi(argv[1])/2));
}
if(atoi(argv[1])==8)
{
ioctl(fp,0,0);
ioctl(fp,0,1);
ioctl(fp,0,2);
ioctl(fp,0,3);
}
if(atoi(argv[1])==9)
{
ioctl(fp,1,0);
ioctl(fp,1,1);
ioctl(fp,1,2);
ioctl(fp,1,3);
}
if(atoi(argv[1])==10)
{
ioctl(fp,0,0);
ioctl(fp,0,1);
}
if(atoi(argv[1])==11)
{
ioctl(fp,1,0);
ioctl(fp,1,1);
}
if(atoi(argv[1])==12)
{
ioctl(fp,0,2);
ioctl(fp,0,3);
}
if(atoi(argv[1])==13)
{
ioctl(fp,1,2);
ioctl(fp,1,3);
}
}