韦东山第12课-字符设备驱动框架、led驱动

来源:互联网 发布:防止域名被腾讯报毒 编辑:程序博客网 时间:2024/05/16 01:21

1 first_drv驱动函数

first_drv.c:

#include <linux/types.h>#include <linux/errno.h>#include <linux/miscdevice.h>#include <linux/slab.h>#include <linux/ioport.h>#include <linux/fcntl.h>#include <linux/mc146818rtc.h>#include <linux/netdevice.h>#include <linux/sched.h>#include <linux/delay.h>#include <asm/io.h>#include <asm/uaccess.h>#include <asm/system.h>#include <linux/delay.h>static int first_drv_open(struct inode *inode, struct file *file){    printk("first_drv_open \n");    return 0; }static ssize_t first_drv_open(struct file *file, const char __user *buf, size_t count, loff_t *ppos);{    printk("first_drv_write \n");    return 0;       }static const struct file_operations first_drv_fops = {.owner = THIS_MODULE,/* owner */.write = first_drv_write,/* write */.open =first_drv_open,/* open */};static int __init first_drv_init(void){register_chrdev(111,"first_drv",&first_drv_fops);//registe dev;rell kernel/* 这是有对比空缺的设备号填写的,也可以用int major=register_chrdev(0,"first_drv",&first_drv_fops); //填0表示自动分配设备号*/                 //主设备号,名字,file_operatins结构体     }static void __exit first_drv_exit(void){ unregister_device(111,"first_drv");//卸载函数               //主设备号,设备名}module_init(first_drv_init);module_exit(first_drv_exit);MODULE_LICENSE("GPL");MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR);


Makefile:

KERN_DIR = /home/book/workspace/jz2440/systems/linux-2.6.22.6all: make -C $(KERN_DIR) M='pwd'  modulesclean:make -C $(KERN_DIR) M='pwd' module cleanrm -rf modules.orderobj-m   += first_drv.o


加载驱动:

cat /proc/devices   //查看驱动

insmod SHT21.ko  //装置驱动 调用module_init(first_drv_init);

rmmod first_drv //卸载驱动调用module_exit(first_drv_init);

lsmod //查看内核中已经加载了哪些模块

mknod /dev/led c 111 0 // 创建设备文件

2 自动创建设备文件

int major=register_chrdev(0,"first_drv",&first_drv_fops); //填0表示自动分配设备号
udev机制,我们就是mdev,
cd /sys/ 目录下有系统设备的信息
mdev根据系统信息创建设备节点。
在驱动注册函数中加入如下代码:
firstdrv_class = class_create(THIS_MODULE, "firstdrv");
firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */
在驱动卸载函数中加入如下代码:
class_device_unregister(firstdrv_class_dev);class_destroy(firstdrv_class);
这个时候驱动加载进去就会自动创建设备文件。
问:为什么可以自动创建呢:
答:驱动程序通过这两个函数,给内核提供了系统信息。一加载就会有文件生成 /sys/class/firstdrv/xyz/dev   mdev根据这些信息创建设备。
问:为什么mdev机制可以根据/sys目录文件的改变生成文件呢?
答:/etc/init.d/rcS 中有“echo /sbin/mdev > /proc/sys/kernel/hotplug” 表示支持热插拔:有驱动加载,就调用mdev
我的系统竟然不支持热插拔,
1 构建根文件系统时busybox 配置为支持hotplug
2 /etc/init.d/rcS 中加入“echo /sbin/mdev > /proc/sys/kernel/hotplug”等
程序框架:
//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 <asm/arch/regs-gpio.h>#include <asm/hardware.h>static struct class *firstdrv_class;static struct class_device*firstdrv_class_dev;static int first_drv_open(struct inode *inode, struct file *file){printk("first_drv_open\n");/* 配置GPF4,5,6为输出 */return 0;}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;}static struct file_operations first_drv_fops = {    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */    .open   =   first_drv_open,         .write=  first_drv_write,   };int major;static int __init first_drv_init(void){ major=register_chrdev(0, "first_drv", &first_drv_fops); // 注册, 告诉内核                 // (主设备号,驱动名字(cat /proc/devices中显示),file_operations类)firstdrv_class = class_create(THIS_MODULE, "firstdrv");                //(THIS_MODULE,驱动名字)firstdrv_class_dev = class_device_create(firstdrv_class, NULL, MKDEV(major, 0), NULL, "xyz"); /* /dev/xyz */              //(firstdrv_class类,父类,驱动号:MKDEV(主号,次号)),struct device *device,mdev要创建的设备名称)return 0;}static void first_drv_exit(void){unregister_chrdev(major, "first_drv"); // 卸载class_device_unregister(firstdrv_class_dev);class_destroy(firstdrv_class);}module_init(first_drv_init);module_exit(first_drv_exit);MODULE_LICENSE("GPL");


3 led驱动

#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;volatile unsigned long *gpfcon = NULL;volatile unsigned long *gpfdat = NULL;static int first_drv_open(struct inode *inode, struct file *file){        *gpfcon &= ~((3<<4*2)|(3<<5*2)|(3<<6*2));        *gpfcon |= ((1<<4*2)|(1<<5*2)|(1<<6*2));      //  *gpfdat=((1<<4)|(1<<5)|(1<<6));    //printk("first_drv_open\n");/* 配置GPF4,5,6为输出 */return 0;}static ssize_t first_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){    int val;    copy_from_user(&val,buf,count);   if(val==1)   {    //电灯    *gpfdat &=~((1<<4)|(1<<5)|(1<<6));    }   else   {    //down    *gpfdat |=((1<<4)|(1<<5)|(1<<6));    }    //printk("first_drv_write\n");return 0;}static struct file_operations first_drv_fops = {    .owner  =   THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */    .open   =   first_drv_open,         .write=  first_drv_write,   };int major;static int __init first_drv_init(void){ 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 */gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);gpfdat = gpfcon + 1;return 0;}static void first_drv_exit(void){unregister_chrdev(major, "first_drv"); // 卸载class_device_unregister(firstdrv_class_dev);class_destroy(firstdrv_class);//iounmap(gpfcon);}module_init(first_drv_init);module_exit(first_drv_exit);MODULE_LICENSE("GPL");


4 copy_from_user

copy_from_user
static inline int copy_from_user(void *to, const void __user *from, int n)
例子:.ko/first_drv_write:copy_from_user(&val, buf, count);  //从buf考值到val中

测试程序用write写数据到驱动first_drv_write
copy_to_user

static inline int copy_to_user(void __user *to, const void *from, int n)


例子:.ko/second_drv_read:copy_to_user(buf, key_vals, sizeof(key_vals)); //将key_cals的值考入buf中
            seconddrvtest.c:read(fd, key_vals, sizeof(key_vals));


4 测试函数

firstdrvtest.c
firstdrvtest.c:  //通过操作文件/dev/led  使用驱动,open write与驱动中的对应
昨天编译一直不能用是因为用的gcc 编译的 应该用arm-linux-gcc -o firstdrvtest 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/xxx", 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;}










原创粉丝点击