#include <linux/init.h>
#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <linux/io.h>
#include "led.h"
#if 0
#define LED_MAJOR 500
#else
#define LED_MAJOR 0
#endif
#define COUNT 3
#define SEQNUM 0
#define DRIVERNAME "myled"
struct cdev *ledcdev;
struct class *cls;
struct device *dce;
volatile unsigned int *virt_RCC;
volatile gpio_t *virt_gpioe;
volatile gpio_t *virt_gpiof;
int major = LED_MAJOR;
int minor = 0;
int mycdevopen(struct inode *inode, struct file *file)
{
int ledmajor, ledminor;
ledmajor = MAJOR(inode->i_rdev);
ledminor = MINOR(inode->i_rdev);
printk("ledmajor=%d ledminor = %d\n", ledmajor, ledminor);
printk("open success\n");
file->private_data = (void *)(ledminor);
return 0;
}
int mycdevrelease(struct inode *inode, struct file *file)
{
printk("release success\n");
return 0;
}
ssize_t mycdevread(struct file *file, char __user *ubuf, size_t size, loff_t *loffs)
{
return 0;
}
ssize_t mycdevwrite(struct file *file, const char __user *ubuf, size_t size, loff_t *loffs)
{
int ledminor;
unsigned long res;
char kbuf[128] = "";
ledminor = (int)file->private_data;
switch (ledminor)
{
case 0:
if (size > sizeof(kbuf))
{
size = sizeof(kbuf);
}
res = copy_from_user(kbuf, ubuf, size);
if (res)
{
printk("copy_from_user failed (err %ld)", res);
return res;
}
if ('0' == kbuf[0])
{
virt_gpioe->ODR &= (~(0x1 << 10));
}
else
{
virt_gpioe->ODR |= (0x1 << 10);
}
break;
case 1:
if (size > sizeof(kbuf))
{
size = sizeof(kbuf);
}
res = copy_from_user(kbuf, ubuf, size);
if (res)
{
printk("copy_from_user failed (err %ld)", res);
return res;
}
if ('0' == kbuf[0])
{
virt_gpiof->ODR &= (~(0x1 << 10));
}
else
{
virt_gpiof->ODR |= (0x1 << 10);
}
break;
case 2:
if (size > sizeof(kbuf))
{
size = sizeof(kbuf);
}
res = copy_from_user(kbuf, ubuf, size);
if (res)
{
printk("copy_from_user failed (err %ld)", res);
return res;
}
if ('0' == kbuf[0])
{
virt_gpioe->ODR &= (~(0x1 << 8));
}
else
{
virt_gpioe->ODR |= (0x1 << 8);
}
break;
}
return 0;
}
struct file_operations fops = {
.open = mycdevopen,
.read = mycdevread,
.write = mycdevwrite,
.release = mycdevrelease};
static int __init
led_init(void)
{
int res, i;
dev_t devt;
// cdev的创建
ledcdev = cdev_alloc();
if (NULL == ledcdev)
{
printk("cdev alloc failed\n");
res = -ENOMEM;
goto ERR1;
}
// cdev的初始化
cdev_init(ledcdev, &fops);
// 条件判断是否动/静态注册设备号
if (LED_MAJOR > 0)
{
res = register_chrdev_region(MKDEV(LED_MAJOR, SEQNUM), COUNT, DRIVERNAME);
if (res)
{
printk("Unable to register char major %d\n", LED_MAJOR);
goto ERR2;
}
major = LED_MAJOR;
minor = SEQNUM;
}
else
{
res = alloc_chrdev_region(&devt, 0, COUNT, DRIVERNAME);
if (res)
{
printk("Could not allocate chrdev region (err %d)\n", -res);
goto ERR2;
}
major = MAJOR(devt);
minor = MINOR(devt);
}
// 字符设备驱动添加至系统
res = cdev_add(ledcdev, MKDEV(major, minor), COUNT);
if (res)
{
printk("Unable register character device add (err %d)\n", -res);
goto ERR3;
}
// 上传目录
cls = class_create(THIS_MODULE, DRIVERNAME);
if (IS_ERR(cls))
{
res = PTR_ERR(cls);
printk("Class create failed (err %d)\n", -res);
goto ERR4;
}
// 上传节点
for (i = 0; i < COUNT; i++)
{
dce = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
if (IS_ERR(dce))
{
res = PTR_ERR(dce);
printk("Device create failed (err %d)\n", res);
goto ERR5;
}
}
//映射RCC_MP_AHB4ENSETR
virt_RCC = (unsigned int *)ioremap(RCC, 4);
if (NULL == virt_RCC)
{
printk("rcc ioremap failed\n");
return -ENOMEM;
}
//映射gpioe的地址
virt_gpioe = (gpio_t *)ioremap(GPIOE, sizeof(gpio_t));
if (NULL == virt_gpioe)
{
printk("gpioe ioremap failed\n");
return -ENOMEM;
}
//映射gpiof的地址
virt_gpiof = (gpio_t *)ioremap(GPIOF, sizeof(gpio_t));
if (NULL == virt_gpiof)
{
printk("gpiof ioremap failed\n");
return -ENOMEM;
}
// RCC使能GPIOE,GPIOF
*virt_RCC |= (0x1 << 4);
*virt_RCC |= (0x1 << 5);
// PE10,PE8设置为输出模式[21:20]=01 [17:16]=01
virt_gpioe->MODER &= (~(0x3 << 20));
virt_gpioe->MODER |= (0x1 << 20);
virt_gpioe->MODER &= (~(0x3 << 16));
virt_gpioe->MODER |= (0x1 << 16);
// PF10设置为输出模式[21:20]=01
virt_gpiof->MODER &= (~(0x3 << 20));
virt_gpiof->MODER |= (0x1 << 20);
//初始化PE10,PE8,PF10为熄灭状态
virt_gpiof->ODR &= (~(0x1 << 10));
virt_gpioe->ODR &= (~(0x1 << 10));
virt_gpioe->ODR &= (~(0x1 << 8));
return 0;
ERR5:
for (--i; i >= 0; i--)
{
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
ERR4:
cdev_del(ledcdev);
ERR3:
unregister_chrdev_region(MKDEV(major, minor), COUNT);
ERR2:
kfree(ledcdev);
ERR1:
return res;
}
static void __exit led_exit(void)
{
int i;
for (i = 0; i < COUNT; i++)
{
device_destroy(cls, MKDEV(major, i));
}
class_destroy(cls);
cdev_del(ledcdev);
unregister_chrdev_region(MKDEV(major, minor), COUNT);
kfree(ledcdev);
}
module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
#ifndef __LED_H__
#define __LED_H__
typedef struct
{
volatile unsigned int MODER;
volatile unsigned int OTYPER;
volatile unsigned int OSPEEDR;
volatile unsigned int PUPDR;
volatile unsigned int IDR;
volatile unsigned int ODR;
} gpio_t;
#define RCC 0x50000A28
#define GPIOE 0x50006000
#define GPIOF 0x50007000
#endif