1、LED驱动实现原理,如图:
2、编写LED驱动
(1)创建LED驱动的设备文件
第一步:使用cdev_init函数初始化cdev
第二步:指定设备号
第三步:使用cdev_add函数将字符设备添加到内核中的字符设备数组中
第四步:使用class_create宏创建struct class
第五步:使用device_create函数创建设备文件
#define DEVICE_NAME "s3c6410_leds" //定义设备文件名称
#define DEVICE_COUNT 1 //创建设备文件的数量
#define S3C6410_LEDS_MAJOR 0 //默认主设备号
#define S3C6410_LEDS_MINOR 234 //默认次设备号
static int major = S3C6410_LEDS_MAJOR; //主设备号
static int minor = S3C6410_LEDS_MINOR; //次设备号
static dev_t dev_number; //设备号
static struct class *leds_class = NULL; //struct class
static struct file_operations dev_ops =
{
.owner = THIS_MODULES,
.unlocked_ioctl = s3c6410_leds_ioctl,
.write = s3c6410_leds_write
};
static struct cdev led_cdev; //描述字符设备的struct cdev
//创建设备文件
static int leds_create_device(void)
{
int ret = 0;
int err = 0;
cdev_init(&leds_cdev, &dev_fops);
leds_cdev.owner = THIS_MODULES;
if (major > 0)
{
dev_number = MKDEV(major, minor);
err = register_chrdev_region(dev_number, DEVICE_COUNT, DEVOCE_NAME);
if (err < 0)
{
printk(KERN_WARNING "register_chrdev_region() failed ");
return err;
}
}
else
{
err = alloc_chrdev_region(&leds_cdev.dev, 10, DEVICE_COUNT, DEVICE_NAME);
if (err < 0)
{
printk(KERN_WARNING "alloc_chrdev_region() failed ");
return err;
}
major = MAJOR(leds_cdev.dev);
minor = MINOR(leds_cdev.dev);
dev_number = leds_cev.dev;
}
ret = cdev_add(&leds_cdev, dev_number, DEVICE_COUNT);
leds_class = class_create(THIS_MODULE, DEVICE_NAME);
device_create(leds_class, NULL, dev_number, NULL, DEVICE_NAME);
return ret;
}
(2)LED驱动初始化函数
static int leds_init(void)
{
int ret;
ret = leds_crerate_device();
printk(DEVICE_NAME " initialized ");
return ret;
}
module_init(leds_init);
(3)LED驱动卸载函数
static void leds_destroy_device(void)
{
device_destory(led_class, dev_number); //移除通过device_create函数创立的字符设备
if (leds_class) //销毁struct class
class_destroy(leds_class);
unregister_chrdev_region(dev_number, DEVICE_NUMBER);
}
static void leds_exit(void)
{
leds_destroy_device();
printk(DEVICE_NAME " exit! ");
}
module_exit(leds_exit);
(4)设置寄存器与初始化LED驱动
static int leds_state = 1;
static void leds_init_gpm(int leds_default)
{
//初始化S3C64XX_GPMCON
int tmp = 0;
tmp = ioread32(S3C64XX_GPMCON);
tmp &= (~0xFFFF);
tmp |= 0x1111;
iowrite32(tmp, S3C64XX_GPMCON);
//初始化S3C64XX_GPMPUD
tmp = ioread32(S3C64XX_GPMPUD);
tmp &= (~0xFF);
tmp |= 0xAA;
iowrite32(tmp, S3C64XX_GPMPUD);
//初始化S3C64XX_GPMDAT
tmp = ioread32(S3C64XX_GPMDAT);
tmp &= (~0xF);
tmp |= leds_default;
iowrite32(tmp, S3C64XX_GPMDAT);
}
static int leds_init(void)
{
int ret;
ret = leds_create_device();
leds_init_gpm(~leds_state);
return ret;
}
(5)控制LED
通过字符串控制LED
static unsigned char mem[4];
static ssize_t s3c6410_leds_write(struct file *file, const char _user *buf, size_t count, loff_t *ppos)
{
unsigned tmp = count;
unsigned long i = 0;
memset(mem, 0, 4);
if (count > 4)
{
tmp = 4;
}
copy_from_user(mem, buf, tmp)
for(i = 0; i < 4; i++)
{
tmp = ioread32(S3C64XX_GPMDAT);
if (mem[i] == '1')
{
tmp &= (~(1 << i));
}
else
{
tmp |= (1 << i);
}
iowrite32(tmp, S3C64XX_GPMDAT);
}
return count;
}
通过I/O命令控制LED
static long s3c6410_leds_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
unsigned tmp;
case 0:
case 1:
if (arg > 4)
return -EINVAL;
tmp = ioreade32(tmp, S3C64XX_GPMDAT);
if (cmd == 1)
tmp &= (~(1 << arg));
else
tmp |=(1 << arg);
iowrite32(tmp, S3C64XX_GPMDAT);
return 0;
default:
return -EINVAL;
}
}