#include <linux/init.h>// __init __exit #include <linux/module.h> // module_init module_exit #include <linux/fs.h> //file_operations #include <asm/uaccess.h> //copy_from_user copy_to_user #include <mach/regs-gpio.h> #include <mach/gpio-bank.h> #include <asm/string.h> #include <linux/ioport.h> //request_mem_region #include <asm/io.h> //ioremap #include <linux/cdev.h> #include <linux/device.h> #define MYNAME "led_dev" #define DEVNUM 1 #define S5PV210_PA_GPIOJ0CON 0xe0200240 volatile unsigned int *rGPJ0CON = NULL; volatile unsigned int *rGPJ0DAT = NULL; static dev_t led_dev_no = 0; /************ 静态使用cdev**********/ //static struct cdev led_cdev; /************ 动态使用cdev**********/ static struct cdev *pled_cdev = NULL; static struct class *pled_dev_class = NULL; static int led_open(struct inode *inode, struct file *file); ssize_t led_read(struct file *file, char __user *user, size_t count, loff_t *loff); ssize_t led_write(struct file *file, const char __user *user, size_t count, loff_t *loff); static int led_release(struct inode *inode, struct file *file); static char kbuf[100] = {0}; static const struct file_operations led_fops = { .owner= THIS_MODULE, .open= led_open, .read = led_read, .write = led_write, .release= led_release, }; int led_open(struct inode *inode, struct file *file) { printk(KERN_INFO "led_open successful\n"); return 0; } ssize_t led_read(struct file *file, char __user *user, size_t ucount, loff_t *loff) { printk(KERN_INFO "led_read successful\n"); if (copy_to_user(user,kbuf , ucount)) { printk(KERN_INFO "copy_to_user fail\n"); return -EINVAL; } printk(KERN_INFO "copy_to_user successful\n"); return strlen(kbuf); } ssize_t led_write(struct file *file, const char __user *user, size_t ucount, loff_t *loff) { printk(KERN_INFO "led_write successful\n"); memset(kbuf,0,sizeof(kbuf)); if (copy_from_user(kbuf, user, ucount)) { printk(KERN_INFO "copy_from_user fail\n"); return -EINVAL; } if(!strcmp(kbuf,"on")) { *rGPJ0CON &=0xff000fff; *rGPJ0CON |=0x00111000; *rGPJ0DAT &=~((0x01<<3)|(0x01<<4)|(0x01<<5)); } else if(!strcmp(kbuf,"off")) { *rGPJ0CON &=0xff000fff; *rGPJ0CON |=0x00111000; *rGPJ0DAT |=((0x01<<3)|(0x01<<4)|(0x01<<5)); } return ucount; printk(KERN_INFO "copy_from_user successful\n"); } int led_release(struct inode *inode, struct file *file) { printk(KERN_INFO "led_release successful\n"); return 0; } // 模块安装函数 static int __init chrdev_init(void) { int ret = -1; int retval = -1; printk(KERN_INFO "chrdev_init successful\n"); /******指定主设备号注册*****/ //led_dev_no = MKDEV(250,0); //retval = register_chrdev_region(led_dev_no, DEVNUM,MYNAME); /******内核自动分配主设备号注册*****/ retval = alloc_chrdev_region(&led_dev_no,0,DEVNUM,MYNAME); if (retval) { printk(KERN_WARNING "alloc_chrdev_region fail\n."); ret = -EINVAL; goto err_reg; } printk(KERN_INFO "alloc_chrdev_region successful major = %d,minor = %d \n",MAJOR(led_dev_no),MINOR(led_dev_no)); /****动态申请cdev实体******/ pled_cdev = cdev_alloc(); printk(KERN_INFO "cdev_alloc successful\n"); cdev_init(pled_cdev, &led_fops); retval = cdev_add(pled_cdev, led_dev_no, DEVNUM); if (retval) { printk(KERN_WARNING "cdev_add fail\n."); ret = -EINVAL; goto err_add; } printk(KERN_INFO "cdev_add successful\n"); // 注册字符设备驱动完成后,添加设备类的操作,以让内核帮我们发信息 // 给udev,让udev自动创建和删除设备文件 pled_dev_class = class_create(THIS_MODULE, "led_musk"); if (IS_ERR(pled_dev_class)) { printk(KERN_WARNING "class_create fail\n."); ret = -EINVAL; goto err_class_create; } device_create(pled_dev_class, NULL, led_dev_no, NULL, "led_dev"); //“led_dev”对应/dev/下的名字 if (request_mem_region(S5PV210_PA_GPIOJ0CON, 8, "GPIOJ0CON") == NULL) { printk(KERN_WARNING "failed to get memory region\n"); ret = -ENOENT; goto err_req; } rGPJ0CON = ioremap(S5PV210_PA_GPIOJ0CON,8); if (rGPJ0CON == NULL) { printk(KERN_WARNING "fail to ioremap() region\n"); ret = -ENOENT; goto err_map; } rGPJ0DAT = rGPJ0CON+1; return 0; err_map: release_mem_region(S5PV210_PA_GPIOJ0CON,8); err_req: class_destroy(pled_dev_class); err_class_create: /***for static cdev******/ //cdev_del(&led_cdev); /***for dynamic cdev******/ cdev_del(pled_cdev); err_add: printk(KERN_INFO "err_add err\n"); unregister_chrdev_region(led_dev_no, DEVNUM); err_reg: return ret; } // 模块卸载函数 static void __exit chrdev_exit(void) { iounmap(rGPJ0CON); release_mem_region(S5PV210_PA_GPIOJ0CON,8); device_destroy(pled_dev_class,led_dev_no); class_destroy(pled_dev_class); /***for static cdev******/ //cdev_del(&led_cdev); /***for dynamic cdev******/ cdev_del(pled_cdev); unregister_chrdev_region(led_dev_no, DEVNUM); printk(KERN_INFO "chrdev_exit successful\n"); } module_init(chrdev_init); module_exit(chrdev_exit); // MODULE_xxx这种宏作用是用来添加模块描述信息 MODULE_LICENSE("GPL");// 描述模块的许可证 MODULE_AUTHOR("musk");// 描述模块的作者 MODULE_DESCRIPTION("module test");// 描述模块的介绍信息 MODULE_ALIAS("alias xxx");// 描述模块的别名信息
相关文章: