#include<linux/module.h>
#include<linux/types.h>
#include<linux/fs.h>
#include<linux/errno.h>
#include<linux/mm.h>
#include<linux/sched.h>
#include<linux/init.h>
#include<linux/cdev.h>
#include<asm/io.h>
#include <asm/system.h>
#include<asm/uaccess.h>
#include <asm/arch/regs-gpio.h>
#include "led.h"
#define LED_NUM 4
#define LED_ON 0
#define LED_OFF (!LED_ON)
#define IS_LEDS(led) ((led) >= LED1 && (led) <= LED4)
#define IS_CTRL(cmd) ((cmd) >= LED_CTRL_ON && (cmd) <= LEDS_CTRL_OFF)
#define LED_MAJOR 212 /*预设的led的主设备号*/
#define led_print(num) printk("%s = 0x%x\n", #num, num)
#define led_printk() printk(KERN_INFO"func %s line = %d\n", __FUNCTION__, __LINE__)
static int led_major = LED_MAJOR;
struct led_dev {
struct cdev cdev;
struct semaphore sem;
};
struct led_dev *led_devp;
static unsigned int led_port[LED_NUM] = {
S3C2410_GPB5,
S3C2410_GPB6,
S3C2410_GPB7,
S3C2410_GPB8
};
static unsigned int led_out[LED_NUM] = {
S3C2410_GPB5_OUTP,
S3C2410_GPB6_OUTP,
S3C2410_GPB7_OUTP,
S3C2410_GPB8_OUTP
};
int led_open(struct inode *inode,struct file *filp)
{
int i;
for (i = 0; i < LED_NUM; i++)
s3c2410_gpio_cfgpin(led_port[i], led_out[i]);
for (i = 0; i < LED_NUM; i++)
s3c2410_gpio_setpin(led_port[i], LED_OFF);
filp->private_data = led_devp;
printk(KERN_INFO"led open driver\n");
return 0;
}
int led_release(struct inode *inode,struct file *filp)
{
int i;
for (i = 0; i < LED_NUM; i++)
s3c2410_gpio_setpin(led_port[i], LED_ON);
filp->private_data = NULL;
return 0;
}
static int led_ioctl(struct inode *inodep,struct file *filp, unsigned int cmd,unsigned long arg)
{
struct led_dev *dev = filp->private_data;
int i;
printk(KERN_INFO"cmd = %d arg = %ld\n", cmd, arg);
if (!IS_CTRL(cmd))
return -1;
down(&dev->sem);
switch (cmd) {
case LED_CTRL_ON:
case LED_CTRL_OFF:
if (!IS_LEDS(arg))
return -1;
s3c2410_gpio_setpin(led_port[arg - 5], cmd);
for (i = 0; i < LED_NUM; i++)
if (i != arg - 5)
s3c2410_gpio_setpin(led_port[i], !cmd);
break;
case LEDS_CTRL_ON:
for (i = 0; i < LED_NUM; i++)
s3c2410_gpio_setpin(led_port[i], LED_ON);
break;
case LEDS_CTRL_OFF:
for (i = 0; i < LED_NUM; i++)
s3c2410_gpio_setpin(led_port[i], LED_OFF);
break;
}
up(&dev->sem);
return 0;
}
static ssize_t led_read(struct file *filp,char __user *buf, size_t size,loff_t *ppos)
{
struct led_dev *dev =filp->private_data;
char tmp[4];
int i;
down(&dev->sem);
for (i = 0; i < LED_NUM; i++)
tmp[i] = s3c2410_gpio_getpin(led_port[i]);
up(&dev->sem);
if (copy_to_user(buf, (void *)tmp, 4))
return -EFAULT;
return 4;
}
static ssize_t led_write(struct file *filp,const char __user *buf, size_t size,loff_t *ppos)
{
struct led_dev *dev = filp->private_data;
char tmp[5];
int i;
if (copy_from_user(tmp, buf, 5))
return -EFAULT;
down(&dev->sem);
for (i = 0; i < LED_NUM; i++)
s3c2410_gpio_setpin(led_port[i], !!(int)(tmp[i] - '0'));
up(&dev->sem);
return size;
}
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.read = led_read,
.write = led_write,
.ioctl = led_ioctl,
.open = led_open,
.release = led_release
};
static void led_setup_cdev(struct led_dev *dev,int index)
{
int err,devno = MKDEV(led_major,index);
cdev_init(&dev->cdev,&led_fops);
dev->cdev.owner = led_fops.owner;
err = cdev_add(&dev->cdev,devno,1);
if (err)
printk(KERN_NOTICE"Error %d adding LED %d\n",err,index);
}
int led_init(void)
{
int result;
dev_t devno = MKDEV(led_major,0);
led_printk();
if (led_major)
result = register_chrdev_region(devno,1,"led");
else {
result = alloc_chrdev_region(&devno,0,1,"led");
led_major = MAJOR(devno);
}
if(result < 0)
return result;
led_devp=kmalloc(sizeof(struct led_dev),GFP_KERNEL);
if(!led_devp)
{
result=-ENOMEM;
goto fail_malloc;
}
memset(led_devp ,0,sizeof(struct led_dev));
led_setup_cdev(led_devp,0);
init_MUTEX(&led_devp->sem);
led_printk();
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return result;
}
void led_exit(void)
{
cdev_del(&led_devp->cdev);
kfree(led_devp);
unregister_chrdev_region(MKDEV(led_major,0),1);
led_printk();
}
MODULE_AUTHOR("Niu Tao");
MODULE_LICENSE("Dual BSD/GPL");
module_param(led_major,int,S_IRUGO);
module_init(led_init);
module_exit(led_exit);
|