Linux\Android 常用驱动框架

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

猜你喜欢

转载自blog.csdn.net/weixin_43069863/article/details/117995964