#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");// 描述模块的别名信息
View Code

相关文章: