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

来源:互联网 发布:c语言编写驱动程序 编辑:程序博客网 时间:2024/05/16 15:20


打开开发板的原理图
找到操作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.6all:make -C $(KERN_DIR) M=`pwd` modules clean:make -C $(KERN_DIR) M=`pwd` modules cleanrm -rf modules.orderobj-m+= first_drv.o



3 将这两个文件上传到linux服务器上,进行编译得到的 first_drv.ko  放到网络文件系统中,启动开发板,启动内核,进入内核,挂接网络文件系统,进入 /mnt目录,查看目前的设备节点是否有123。
starting pid 767, tty '/dev/ttySAC0': '/bin/sh'# lsbin         lib         mnt         sbin        usrdev         linuxrc     proc        sysetc         lost+found  root        tmp# cd /mnt/# ls# cd ../# ifconfigeth0      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/# lsbin             first_drv.ko    mnt             sysbutton_drv.ko   firstdrvtest    myleds.ko       test.txtbuttontest      forth_drv.ko    myleds2.ko      test_drv.kocfbcopyarea.ko  forthdrvtest    proc            testdrv_testcfbfillrect.ko  hello           sbin            third_drv.kocfbimgblt.ko    hello.c         second_drv.ko   thirddrvtestdev             lcd.ko          seconddrvtest   uImageetc             ledtest         signal          uImage_nolcdfifth_drv.ko    lib             sixth_drv.ko    usrfifthdrvtest    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 ppdev116 alsa128 ptm136 pts180 usb189 usb_device204 s3c2410_serial252 first_drv253 usb_endpoint254 rtcBlock devices:  1 ramdisk  7 loop  8 sd 31 mtdblock 65 sd 66 sd 67 sd 68 sd 69 sd 70 sd 71 sd128 sd129 sd130 sd131 sd132 sd133 sd134 sd135 sd179 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 ppdev116 alsa128 ptm136 pts180 usb189 usb_device204 s3c2410_serial252 first_drv253 usb_endpoint254 rtcBlock devices:  1 ramdisk  7 loop  8 sd 31 mtdblock 65 sd 66 sd 67 sd 68 sd 69 sd 70 sd 71 sd128 sd129 sd130 sd131 sd132 sd133 sd134 sd135 sd179 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");







0 0
原创粉丝点击