嵌入式驱动编写-第一个驱动程序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/joshua_love/article/details/53047128


打开开发板的原理图
找到操作LED的寄存器
1 确定运行环境正常
1 PC,linux虚拟机,JZ2440开发板之前可以互相ping通

查看设备类型









1  编写驱动程序
#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 <asm/arch/regs-gpio.h>
#include <asm/hardware.h>


//定义一个open函数
static int first_drv_open(struct inode *inode, struct file *file)
{	
	printk("first_drv_open/n");
	return 0;
}
//定义一个write函数
static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
	printk("first_drv_write/n");
	return 0;
}
//定义一个file_operations 结构体
static struct file_operations first_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   first_drv_open,     //结构体的函数是定义的
	.write	=	first_drv_write,	//结构体的函数是定义的
};


//定义入口函数
static int first_drv_init(void)
{
	//app找到这个驱动  不是根据名字  是根据 设备类型 主设备号
register_chrdev(123, "first_drv", &first_drv_fops);// 注册, 告诉内核 主设备号  名字 定义的结构体


return 0;
}
//定义出口函数
static void first_drv_exit(void)
{
unregister_chrdev(123, "first_drv");
}
//通过module修饰成为linux内核可识别的入口和出口函数
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");



2 编写makefile来进行编译
KERN_DIR = /work/system/linux-2.6.22.6

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



3 将这两个文件上传到linux服务器上,进行编译得到的 first_drv.ko  放到网络文件系统中,启动开发板,启动内核,进入内核,挂接网络文件系统,进入 /mnt目录,查看目前的设备节点是否有123。
starting pid 767, tty '/dev/ttySAC0': '/bin/sh'
# ls
bin         lib         mnt         sbin        usr
dev         linuxrc     proc        sys
etc         lost+found  root        tmp
# cd /mnt/
# ls
# cd ../
# ifconfig
eth0      Link encap:Ethernet  HWaddr 00:60:6E:33:44:55  
          inet addr:192.168.1.17  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:2 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:128 (128.0 B)  TX bytes:0 (0.0 B)
          Interrupt:51 Base address:0xa000 

# ifconfig eth0 192.168.0.105
#  mount -t nfs -o nolock,vers=2 192.168.0.104:/work/nfs_root/first_fs/ mnt
# cd /
/             /etc/         /mnt/         /sbin/        /usr/
/bin/         /lib/         /proc/        /sys/
/dev/         /lost+found/  /root/        /tmp/
# cd /mnt/
# ls
bin             first_drv.ko    mnt             sys
button_drv.ko   firstdrvtest    myleds.ko       test.txt
buttontest      forth_drv.ko    myleds2.ko      test_drv.ko
cfbcopyarea.ko  forthdrvtest    proc            testdrv_test
cfbfillrect.ko  hello           sbin            third_drv.ko
cfbimgblt.ko    hello.c         second_drv.ko   thirddrvtest
dev             lcd.ko          seconddrvtest   uImage
etc             ledtest         signal          uImage_nolcd
fifth_drv.ko    lib             sixth_drv.ko    usr
fifthdrvtest    linuxrc         sixthdrvtest
# insmod first_drv.ko 
# remmod first_drv.ko 
-sh: remmod: not found
# cat /proc/devices 
Character devices:
  1 mem
  2 pty
  3 ttyp
  4 /dev/vc/0
  4 tty
  4 ttyS
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  6 lp
  7 vcs
 10 misc
 13 input
 14 sound
 29 fb
 90 mtd
 99 ppdev
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
204 s3c2410_serial
252 first_drv
253 usb_endpoint
254 rtc

Block devices:
  1 ramdisk
  7 loop
  8 sd
 31 mtdblock
 65 sd
 66 sd
 67 sd
 68 sd
 69 sd
 70 sd
 71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc
# 


确定后,开始挂载设备节点,insmod  first_drv.ko ,
通过# cat /proc/devices  查看当前的设备节点 看到挂接成功
通过rmmod  first_drv 命令后 再次查看 发现你123的设备节点没有了



4 修改一下驱动程序,在第一个驱动程序中,设备号是写死的,这样我们不确定这个设备号是否已经被占用。
#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 <asm/arch/regs-gpio.h>
#include <asm/hardware.h>


//定义一个open函数
static int first_drv_open(struct inode *inode, struct file *file)
{	
	printk("first_drv_open/n");
	return 0;
}
//定义一个write函数
static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
	printk("first_drv_write/n");
	return 0;
}
//定义一个file_operations 结构体
static struct file_operations first_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   first_drv_open,     //结构体的函数是定义的
	.write	=	first_drv_write,	//结构体的函数是定义的
};

int major;
//定义入口函数
static int first_drv_init(void)
{
	//app找到这个驱动  不是根据名字  是根据 设备类型 主设备号
//主设备号 随便写个123  写 0会自动分配
major = register_chrdev(0, "first_drv", &first_drv_fops);// 注册, 告诉内核 主设备号  名字 定义的结构体


return 0;
}
//定义出口函数
static void first_drv_exit(void)
{
unregister_chrdev(major, "first_drv");
}
//通过module修饰成为linux内核课识别的入口和出口函数
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");




重复之前的操作,上传,编译,运行,看到自动分配的是252
# insmod  first_drv.ko 
# cat /proc/devices 
Character devices:
  1 mem
  2 pty
  3 ttyp
  4 /dev/vc/0
  4 tty
  4 ttyS
  5 /dev/tty
  5 /dev/console
  5 /dev/ptmx
  6 lp
  7 vcs
 10 misc
 13 input
 14 sound
 29 fb
 90 mtd
 99 ppdev
116 alsa
128 ptm
136 pts
180 usb
189 usb_device
204 s3c2410_serial
252 first_drv
253 usb_endpoint
254 rtc

Block devices:
  1 ramdisk
  7 loop
  8 sd
 31 mtdblock
 65 sd
 66 sd
 67 sd
 68 sd
 69 sd
 70 sd
 71 sd
128 sd
129 sd
130 sd
131 sd
132 sd
133 sd
134 sd
135 sd
179 mmc


5 写测试程序调用驱动程序
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv)
{
	int fd;
	int val = 1;
	fd = open("/dev/xxx",O_RDWR);
	if(fd<0){
		printf("can't open!\n");
	}
	write(fd,&val,4);
	return 0;
}


上传到服务器上编译,放到网络文件系统下,进入开发板来运行

# ./firstdev_test 
can't open!
# 


发现没有这个目录,我们来创建这个设备目录
# mknod   /dev/xxx c  252 0


再次运行,发现打印出驱动程序的实现。
# ./firstd
./firstdev_test  ./firstdrvtest
# ./firstdev_test 
first_drv_open/nfirst_drv_write/n# 


6 继续修改代码,设备号每次都通过 cat来获得太麻烦
#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 <asm/arch/regs-gpio.h>
#include <asm/hardware.h>

static struct class *firstdrv_class;
static struct class_device	*firstdrv_class_dev;
//定义一个open函数
static int first_drv_open(struct inode *inode, struct file *file)
{	
	printk("first_drv_open/n");
	return 0;
}
//定义一个write函数
static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
{
	printk("first_drv_write/n");
	return 0;
}
//定义一个file_operations 结构体
static struct file_operations first_drv_fops = {
    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
    .open   =   first_drv_open,     //结构体的函数是定义的
	.write	=	first_drv_write,	//结构体的函数是定义的
};

int major;
//定义入口函数
static int first_drv_init(void)
{
	//app找到这个驱动  不是根据名字  是根据 设备类型 主设备号
//主设备号 随便写个123  写 0会自动分配
major = register_chrdev(0, "first_drv", &first_drv_fops);// 注册, 告诉内核 主设备号  名字 定义的结构体
	firstdrv_class = class_create(THIS_MODULE, "firstdrv");

	firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */

return 0;
}
//定义出口函数
static void first_drv_exit(void)
{
unregister_chrdev(major, "first_drv");
class_device_unregister(firstdrv_class_dev);
class_destroy(firstdrv_class);
}
//通过module修饰成为linux内核课识别的入口和出口函数
module_init(first_drv_init);
module_exit(first_drv_exit);
MODULE_LICENSE("GPL");







阅读更多

没有更多推荐了,返回首页