内核驱动笔记(二)——beep驱动

来源:互联网 发布:linux服务器优点 编辑:程序博客网 时间:2024/06/03 20:47

一、字符设备驱动的设计流程
1、定义一个字符设备---cdev
2、定义一个文件操作集并对其进行初始化
3、给这个字符设备申请设备号
4、字符设备初始化 cdev_init()
5、将字符设备注册到内核 cdev_add()
6、申请物理地址内存区作为一个资源
7、使用内存的动态映射,由物理地址得到虚拟地址
8、通过虚拟地址访问寄存器
9、创建设备文件。


#include <linux/io.h>#include <linux/fs.h>#include <linux/cdev.h>#include <linux/device.h>#include <linux/ioport.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/uaccess.h>static struct cdev buzzer_drv; //定义字符设备 static unsigned int buzzer_major = 200; //主设备号若是0,是动态申请;若不是,则默认是静态注册static unsigned int buzzer_minor = 0;   //次设备号 static dev_t buzzer_drv_num; //设备号static struct class  *class;     //类static struct device *device;           //设备名称 static struct resource *buzzer_res;     //申请物理内存static unsigned long *GPD0CON;          //存放物理内存映射后的虚拟地址static unsigned long *GPD0DAT; static int buzzer_open (struct inode *inode,struct file *filp){printk ("ready to open\n");*GPD0CON &= ~(0xf<<0);*GPD0CON |=  (0x1<<0); //输出状态*GPD0DAT &= ~(0xf<<0); //高电平,蜂鸣器不响return 0;} static int buzzer_write (struct file *filp,const char __user *buf,size_t len,loff_t *ppos){int err,ret;printk ("ready to write\n");err = copy_from_user(&ret,buf,len);if (err != 0){printk ("copy from user failed\n");return -EFAULT;}printk ("%d\n",ret);/*根据用户程序决定蜂鸣器情况*/*GPD0DAT ^= (ret<<0);return 0;} static int buzzer_release (struct inode *inode, struct file *filp){printk ("release success\n");return 0;} /*定义文件操作集*/static struct file_operations buzzer_drv_fops = {.owner = THIS_MODULE,.open  = buzzer_open,.write = buzzer_write,.release = buzzer_release,}; /*驱动初始化及安装函数*/static int __init buzzer_init (void){int err;buzzer_drv_num = MKDEV (buzzer_major,buzzer_minor);//驱动设备的设备号/*注册设备*/err = register_chrdev_region (buzzer_drv_num,1,"buzzer_drv");if (err < 0){printk ("get buzzer_drv_num failed\n");return err;}/*初始化字符设备*/cdev_init (&buzzer_drv,&buzzer_drv_fops);/*字符设备添加至内核*/err = cdev_add (&buzzer_drv,buzzer_drv_num,1);if (err < 0){printk ("add failed\n");goto add_failed;}/*自动创建设备文件*//*注册一个类*/class = class_create (THIS_MODULE,"buzzer_drv");if (IS_ERR(class)){printk ("create class failed\n");goto add_failed;}/*从属的类下,在/dev目录下创建设备节点*/device = device_create (class,NULL,buzzer_drv_num,NULL,"buzzer_drv");if (IS_ERR(device)){printk ("create device failed\n");goto device_failed;}printk ("init success\n");/*led灯初始化*//*申物理内存区域*/buzzer_res = request_mem_region(0xe02000A0,8,"buzzer_drv");if (buzzer_res == NULL){printk ("request memory failed\n");goto request_failed;}/*映射虚拟内存*/GPD0CON =(unsigned long *) ioremap (0xe02000A0,8);if (GPD0CON == NULL){printk ("ioremap failed\n");goto ioremap_failed;//return -EFAULT;}GPD0DAT = GPD0CON + 0x1;printk ("buzzer init success\n");return 0;ioremap_failed:/*释放物理内存空间*/release_mem_region (0xe02000A0,8);request_failed:/*销毁设备节点*/device_destroy (class,buzzer_drv_num);device_failed:/*销毁类*/class_destroy(class);add_failed:/*删除字符设备*/cdev_del (&buzzer_drv);/*注销设备号*/unregister_chrdev_region (buzzer_drv_num,1);return -1;} /*驱动卸载*/static void __exit buzzer_exit (void){/*取消IO内存映射*/iounmap (GPD0CON);/*释放物理内存空间*/release_mem_region (0xe02000A0,8);/*销毁设备节点*/device_destroy (class,buzzer_drv_num);    /*清除类*/class_destroy  (class);/*删除字符设备*/    cdev_del    (&buzzer_drv);/*注销设备号*/unregister_chrdev_region (buzzer_drv_num,1);printk ("exit success\n");} /*驱动入口*/module_init (buzzer_init);/*驱动出口*/module_exit (buzzer_exit); /*内核模块描述,使用#modinfo查看相应信息*/MODULE_AUTHOR  ("yuan");MODULE_LICENSE ("GPL");





0 0
原创粉丝点击