#include <linux/module.h>
#include <linux/version.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/leds.h>
#include <linux/serial_core.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/gpio.h>
#include <linux/moduleparam.h>
#include <linux/miscdevice.h>
#include <linux/device.h>
#include <asm/uaccess.h>

#define DEVICE_NAME "am335x_leds"//设备名称
#define DEVICE_COUNT 1//设备数量
#define LEDS_NUM_MAX 4//设备数量

#define GPIO_TO_PIN(bank, gpio) (32 * (bank) + (gpio))

static int am335x_leds_major = 0;//主设备号
static int am335x_leds_minor = 0;//次设备号
static int am335x_leds_gpio[LEDS_NUM_MAX] = {0};

static int mem_size = 0;

static dev_t dev_number;
static struct class *am335x_leds_class = NULL;

struct cdev am335x_leds_cdev;

static int am335x_leds_remove(struct platform_device *am335x_leds_dev);
static int am335x_leds_probe(struct platform_device *am335x_leds_dev);

static struct gpio_led am335x_gpio_leds[] = {
{
.name = "LED1",
.gpio = GPIO_TO_PIN(0, 12), /* LED1 */
},
{
.name = "LED2",
.gpio = GPIO_TO_PIN(0, 13), /* LED2 */
},
};

static struct gpio_led_platform_data am335x_gpio_leds_info = {
.leds = am335x_gpio_leds,
.num_leds = ARRAY_SIZE(am335x_gpio_leds),
};

static void am335x_leds_dev_release(struct device * dev) //释放函数
{

}

static struct platform_device am335x_leds_dev = {
.name = "am335x_leds",
.id = -1,
.dev = {
.platform_data = &am335x_gpio_leds_info,
.release = am335x_leds_dev_release,
},
};

struct platform_driver am335x_leds_drv = {
.probe = am335x_leds_probe, //当与设备匹配,则调用该函数
.remove = am335x_leds_remove, //删除设备

.driver = {
.owner = THIS_MODULE,
.name = "am335x_leds", //与设备名称一样
}
};

static long am335x_leds_ioctl(struct file *filp,unsigned int cmd,unsigned long arg)
{
if((cmd < mem_size)&&(arg < 2))
gpio_set_value(am335x_leds_gpio[cmd],arg);
return 0;
}

static int am335x_leds_open(struct inode *inodep, struct file * filep) // 打开设备
{
int ret = 0;

printk(KERN_ALERT "%s,%d\n", __func__, __LINE__);

return ret;
}

static ssize_t am335x_leds_read(struct file *filp,char __user *buf, size_t size, loff_t *ppos)
{
int ret = -1;
char mem[mem_size];
//读取数据到用户空间

if(copy_to_user(buf,mem,size))
{
ret= -EFAULT;
printk("copyfrom user failed\n");
}
else{
ret= size;
printk("read%d bytes from dev\n", size);
}
return ret;
}

static ssize_t am335x_leds_write(struct file *filp,const char __user *buf, size_t size, loff_t *ppos)//注意:第二个参数和read方法不同
{
int i,ret = -1;
unsigned tmp = size;
char mem[mem_size];


memset(mem,0,mem_size);

if(size > mem_size)
{
tmp = mem_size;
}
if(copy_from_user(mem,buf,size))
{
ret= -EFAULT;
printk("copyfrom user failed\n");

}
else{
ret= size;
for(i=0;i<mem_size;i++)
{
if(mem[i] == '1')
{
gpio_set_value(am335x_leds_gpio[i],0);
}
else
{
gpio_set_value(am335x_leds_gpio[i],1);
}
}
printk("write%d bytes to dev\n", size);
}
return ret;
}

static int am335x_leds_drv_release(struct inode * inodep, struct file * filep) // 关闭设备
{
printk("%s,%d\n", __func__, __LINE__);

// gpio_free(AM335X_LEDS_GPIO);

return 1;
}

struct file_operations am335x_leds_fops =
{
.owner = THIS_MODULE,
.unlocked_ioctl = am335x_leds_ioctl,
.open = am335x_leds_open,
.release = am335x_leds_drv_release,
.read = am335x_leds_read,
.write = am335x_leds_write,
};

static int am335x_leds_gpio_init(void)
{
int i,ret = -1;

for(i = 0;i < mem_size;i++)
{
ret = gpio_request(am335x_leds_gpio[i],"GPIO0");//请求查看12引脚是否被占用
if(ret<0)
{
printk(KERN_ALERT "gpio%d request failed\n",am335x_leds_gpio[i]);
}
ret = gpio_direction_output(am335x_leds_gpio[i],1);//设置为输出模式
if(ret<0)
{
printk(KERN_ALERT "gpio%d set output failed\n",am335x_leds_gpio[i]);
}
}
return ret;
}

static int am335x_leds_probe(struct platform_device *pdev)
{

int i,ret = 0;
// struct resource *res;
struct device *am335x_leds_device = NULL;
struct gpio_led_platform_data *leds_data;
struct gpio_led *ledgpio;
printk(KERN_ALERT "%s,%d\n", __func__, __LINE__);

leds_data = dev_get_platdata(&pdev->dev);

mem_size = leds_data->num_leds;
printk(KERN_ALERT "leds_size is %d\n",mem_size);

if(mem_size > LEDS_NUM_MAX)
mem_size = LEDS_NUM_MAX;

ledgpio = leds_data->leds;

for(i = 0;i < mem_size;i++)
{
am335x_leds_gpio[i] = ledgpio[i].gpio;
printk(KERN_ALERT "led%d gpio is %d\n",i,am335x_leds_gpio[i]);
}

am335x_leds_gpio_init();

//cdev_init()函数用于初始化 cdev 的成员,并建立 cdev 和 file_operations 之间的连接
cdev_init(&am335x_leds_cdev, &am335x_leds_fops);
am335x_leds_cdev.owner = THIS_MODULE;

/**在调用 cdev_add()函数向系统注册字符设备之前,
*应首先调用 register_chrdev_region()或alloc_chrdev_region()函数向系统申请设备号
**/
if (am335x_leds_major)//静态申请
{
//使用下列宏则可以通过主设备号和次设备号生成 dev_t
dev_number = MKDEV(am335x_leds_major, am335x_leds_minor);
ret = register_chrdev_region(dev_number, DEVICE_COUNT, DEVICE_NAME);
printk(KERN_ALERT "Sucees register_chrdev_region.\n");
}
else //动态分配
{
ret = alloc_chrdev_region(&am335x_leds_cdev.dev, 0, DEVICE_COUNT, DEVICE_NAME);
am335x_leds_major = MAJOR(am335x_leds_cdev.dev);
am335x_leds_minor = MINOR(am335x_leds_cdev.dev);
// dev_number = MKDEV(am335x_leds_major, am335x_leds_minor);
dev_number = am335x_leds_cdev.dev;
printk(KERN_ALERT "Sucees alloc_chrdev_region. The Major is %d,The minor is %d\n",am335x_leds_major,am335x_leds_minor);
}
if(ret)
{
printk(KERN_ALERT "Failed to register_chrdev_region.\n");
return ret;
}

//系统添加一个 cdev,完成字符设备的注册。
ret = cdev_add(&am335x_leds_cdev, dev_number, DEVICE_COUNT);
if(ret)
{
printk(KERN_ALERT " Failed to cdev_add [Error] %d adding am335x_leds%d", ret, DEVICE_COUNT);
unregister_chrdev_region(dev_number, 1);
return ret;
}
//am335x_leds_class = class_create(THIS_MODULE,DEVICE_NAME);
am335x_leds_class = class_create(THIS_MODULE,"am335x_leds");

if(IS_ERR(am335x_leds_class))
{
printk(KERN_ALERT "failed in creating class.\n");
return -1;
}
else
{
printk(KERN_ALERT "Sucees in creating class.\n");
}
am335x_leds_device = device_create(am335x_leds_class,NULL,dev_number,NULL,"am335x_leds");

if(IS_ERR(am335x_leds_device))
{
device_destroy(am335x_leds_class,dev_number);
if(am335x_leds_class)
class_destroy(am335x_leds_class);
printk(KERN_ALERT "failed in creating device.\n");
return -1;
}
else
{
printk(KERN_ALERT "Sucees in creating device.\n");
}

return 0;
}

static int am335x_leds_remove(struct platform_device *pdev)
{
int i;

printk(KERN_ALERT "%s,%d\n", __func__, __LINE__);

for(i=0;i<mem_size;i++)
{
gpio_free(am335x_leds_gpio[i]);
}
device_destroy(am335x_leds_class,dev_number);
if(am335x_leds_class)
class_destroy(am335x_leds_class);
//删除一个 cdev,完成字符设备的注销。
cdev_del(&am335x_leds_cdev);
//在调用cdev_del()函数从系统注销字符设备之后,unregister_chrdev_region()应该被调用以释放原先申请的设备号
unregister_chrdev_region(dev_number, DEVICE_COUNT);
return 0;
}

static int __init am335x_leds_init(void)
{
int err;

err = platform_device_register(&am335x_leds_dev);
if (err)
{
pr_err(KERN_ALERT "failed to register gpio led device\n");
goto device_reg_err;
}

err = platform_driver_register(&am335x_leds_drv);
if (err)
{
pr_err(KERN_ALERT "failed to register gpio led driver\n");
goto driver_reg_err;
}
return 0;
device_reg_err:
platform_device_unregister(&am335x_leds_dev);
driver_reg_err:
platform_driver_unregister(&am335x_leds_drv);
return -1;
}

static void __exit am335x_leds_exit(void)
{
platform_device_unregister(&am335x_leds_dev);
platform_driver_unregister(&am335x_leds_drv);
}

module_init(am335x_leds_init);
module_exit(am335x_leds_exit);

MODULE_AUTHOR("lazybeee");
MODULE_LICENSE("GPL");

posted on 2019-02-27 12:57  懒床小蜜蜂  阅读(145)  评论(0编辑  收藏  举报