driver.c
#include <linux/device.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/stat.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include "driver.h"
static int xxx_dt_parse(struct platform_device *pdev)
{
int m, n;
unsigned char i;
struct device_node *node, *child;
struct xxx_dev *ldev;
enum of_gpio_flags flags;
ldev = platform_get_drvdata(pdev);
node = pdev->dev.of_node;
if (!node) {
printk("get node fail !!! \n");
return -ENODEV;
}
printk("%d \n", of_get_available_child_count(node));
i=0;
for_each_child_of_node(node, child){
enum of_gpio_flags flags;
if(i == 0)
{
ldev->d.pin = of_get_gpio_flags(node->child, 0, &flags);
pr_info("led_gpio = %u\n", ldev->d.pin);
i++;
}
else
{
ldev->c.pin = of_get_gpio_flags(node->child, 0, &flags);
pr_info("led_gpio = %u\n", ldev->c.pin);
}
}
ldev->led_gpio = of_get_named_gpio_flags(node, "xxx_sda", 0, &flags);
// ldev->led_gpio = of_get_gpio_flags(node->child, 0, &flags);
if (!gpio_is_valid(ldev->led_gpio)) {
pr_err("gpio %d is not valid\n", ldev->led_gpio);
return -EINVAL;
}
ldev->d.pin = ldev->led_gpio;
ldev->d.active_low = flags & OF_GPIO_ACTIVE_LOW;
pr_info("led_gpio = %u\n", ldev->d.pin);
pr_info("active_low = %u\n", ldev->d.active_low);
m = gpio_request(ldev->d.pin, "data");
n = gpio_direction_output(ldev->d.pin, 1);
printk("\nrequst, pin: %d, %d\n", m, n);
return 0;
}
static long xxx_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch(cmd) {
case LED_RING:
printk("ring !!! \n");
break;
case LED_USB:
printk("usb !!! \n");
break;
}
return 0;
}
static ssize_t xxx_write(struct file *file,const char __user *buf,size_t count,loff_t *pos)
{
char lbuf[30];
if (count >= sizeof(lbuf))
count = sizeof(lbuf)-1;
if (copy_from_user(lbuf, buf, count))
return -EFAULT;
lbuf[count] = 0;
return count;
}
static int xxx_open(struct inode *inode,struct file *file)
{
printk(" open!!! \n");
return 0;
}
static const struct file_operations mis_fops = {
.owner = THIS_MODULE,
.open = xxx_open,
.write = xxx_write,
.unlocked_ioctl = xxx_ioctl,
};
struct miscdevice mis = {
.minor = 255,
.name = "xxx",
.fops = &mis_fops,
};
static int xxx_probe(struct platform_device *pdev)
{
ldev = kzalloc(sizeof(struct xxx_dev), GFP_KERNEL);
platform_set_drvdata(pdev, ldev);
if (xxx_dt_parse(pdev)) {
pr_info("get dt error!");
return 0;
}
ldev->cdev = &mis;
printk("\n misc_register is %d\n", misc_register(ldev->cdev));
return 0;
}
void obj_test_release(struct kobject *kobject);
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf);
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count);
struct attribute test_attr = {
.name = "xxx",
.mode = S_IRWXUGO,
};
static struct attribute *def_attrs[] = {
&test_attr,
NULL,
};
struct sysfs_ops obj_test_sysops =
{
.show = kobj_test_show,
.store = kobj_test_store,
};
struct kobj_type ktype =
{
.release = obj_test_release,
.sysfs_ops=&obj_test_sysops,
.default_attrs=def_attrs,
};
void obj_test_release(struct kobject *kobject)
{
printk("eric_test: release .\n");
}
//读该文件的时候调用show 函数
ssize_t kobj_test_show(struct kobject *kobject, struct attribute *attr,char *buf)
{
printk("have show.\n");
printk("attrname:%s.\n", attr->name);
sprintf(buf,"%s\n",attr->name);
return strlen(attr->name)+2;
}
//写该文件的时候调用store 函数
ssize_t kobj_test_store(struct kobject *kobject,struct attribute *attr,const char *buf, size_t count)
{
printk("store \n");
return 0;
}
static const struct of_device_id xxx_dt_match[] = {
{
.compatible = "xxx", //compate with dts
},
{
},
};
static struct platform_driver xxx_driver = {
.driver = {
.name = "xxx",
.owner = THIS_MODULE,
.of_match_table = xxx_dt_match,
},
.probe = xxx_probe,
};
struct kobject kobj;
static int xxx_init(void)
{
if( platform_driver_register(&xxx_driver) ) {
pr_err("failed to register driver\n");
return -ENODEV;
}
if( kobject_init_and_add(&kobj,&ktype,NULL,"kobj_text" ){
pr_err("failed to init_and_add kobj\n");
return -ENODEV;
}
return 0;
}
static void xxx_exit(void)
{
printk("exit !!! \n");
kobject_del(&kobj);
}
module_init(xxx_init);
module_exit(xxx_exit);
driver.h
#ifndef _DRIVER_H_
#define _DRIVER_H_
#include <linux/proc_fs.h>
#include <linux/miscdevice.h>
/*ioctl 宏声明*/
#define IOC_MAGIC 'a'
/*定义命令*/
#define LED_RING _IO(IOC_MAGIC, 0)
#define LED_USB _IO(IOC_MAGIC, 1)
enum {
LED_GPIO_STATE_OFF = 0,
LED_GPIO_STATE_ON,
};
struct dev_gpio {
const char *name;
unsigned int pin;
unsigned int active_low;
unsigned int state;
};
struct xxx_dev {
struct dev_gpio c;
struct dev_gpio d;
struct miscdevice *cdev;
int gpio;
int flag;
};
struct xxx_dev *ldev;
#endif