#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define LEDS_NAME "led"
#define LEDS_COUNT 1
#define LEDS_MAJOR 0
#define LEDS_MINOR 0
MODULE_LICENSE("Dual BSD/GPL");
dev_t devid;
static struct cdev *led_dev;
static struct class *led_class;
static unsigned long led_pin[] = {
S3C2410_GPB(5),
S3C2410_GPB(6),
S3C2410_GPB(7),
S3C2410_GPB(8),
};
static unsigned int led_cfg[] = {
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
S3C2410_GPIO_OUTPUT,
};
static char led_flag[4]={
'1',
'1',
'1',
'1',
};
static int led_open(struct inode *inode, struct file *filp)
{
int i;
for(i = 0; i < 4 ;i ++)
{
s3c2410_gpio_cfgpin(led_pin[i],led_cfg[i]);
s3c2410_gpio_setpin(led_pin[i],(int)(led_flag[i] - '0'));
}
printk("open led ok\n");
return 0;
}
static ssize_t led_read(struct file *filp, char __user *buff, size_t size, loff_t *ppos)
{
if (size > 4)
{
return -EFAULT;
}
if(copy_to_user(buff,(void *)led_flag,size))
{
return -EFAULT;
}
return size;
}
static ssize_t led_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
int i;
if (size > 4)
{
return -EFAULT;
}
if(copy_from_user(led_flag,buf,size))
{
return -EFAULT;
}
for(i = 0; i < size;i ++)
{
s3c2410_gpio_setpin(led_pin[i],(int)(led_flag[i] - '0'));
}
return size;
}
static int led_ioctl(struct inode *inodep,struct file *filp, unsigned int cmd,unsigned long arg)
{
if((cmd > 1)||(arg > 3))
{
return -EFAULT;
}
switch(cmd)
{
case 0:
case 1:
s3c2410_gpio_setpin(led_pin[arg],cmd);
led_flag[arg] = cmd + '0';
return 0;
break;
default:
return -EINVAL;
break;
}
}
static int led_release(struct inode *inode, struct file *filp)
{
int i;
for(i =0 ;i < 4;i++)
{
s3c2410_gpio_setpin(led_pin[i],1);
}
return 0;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.ioctl = led_ioctl,
.release = led_release,
};
static void led_setup(void)
{
int ret;
cdev_init(led_dev,&led_fops); //初始化 cdev
led_dev->owner = THIS_MODULE;
led_dev->ops = &led_fops;
ret = cdev_add(led_dev,devid,LEDS_COUNT);//添加注册设备
if(IS_ERR(&ret))
{
printk("Error:%d adding leds!\n",ret);
}
}
static int __init led_init(void)
{
int ret;
if(LEDS_MAJOR)//判断是动态申请设备号还是静态申请
{
devid = MKDEV(LEDS_MAJOR,LEDS_MINOR);//根据主、次设备号 得到设备号
ret = register_chrdev_region(devid,LEDS_COUNT,LEDS_NAME);//静态申请函数
}
else
{
ret = alloc_chrdev_region(&devid,LEDS_MINOR,1,LEDS_NAME);//动态申请函数
}
if(ret < 0)
{
printk("Can't register major number!\n");
return ret;
}
led_dev = kmalloc(sizeof(struct cdev),GFP_KERNEL);//为cdev结构动态申请内核空间
if(!led_dev)
{
ret = -ENOMEM;//失败返回值
goto fail_malloc;
}
memset(led_dev,0,sizeof(struct cdev));//格式化led_dev设备结构
led_setup();
led_class = class_create(THIS_MODULE,LEDS_NAME);//注册一个类,使mdev在"dev/"下面为设备建立设备节点
if(IS_ERR(led_class))
{
printk("Error:Failed to create led_class!\n");
return -1;//建立设备节点失败
}
device_create(led_class,NULL,devid,NULL,LEDS_NAME);//创建设备节点 名字为LEDS_NAME
printk("%s Init ok!\n",LEDS_NAME);
return 0;
fail_malloc:
unregister_chrdev_region(devid,LEDS_COUNT);//注销从devid这个设备号开始的LEDS_COUNT个设备号
return ret;
}
static void __exit led_exit(void)
{
cdev_del(led_dev);
kfree(led_dev);
unregister_chrdev_region(devid,LEDS_COUNT);
device_destroy(led_class, devid);
class_destroy(led_class);
}
module_init(led_init);
module_exit(led_exit);
阅读(237) | 评论(0) | 转发(0) |