嵌入式笔记-字符设备驱动调试源码

本文档展示了如何在Linux内核中创建一个字符设备驱动,用于控制GPIO口。驱动模板包含了设备注册、打开、释放、读写操作,并通过设备树从DTB获取GPIO。驱动支持读写接口,用户空间可以通过写入特定格式的字符串来切换GPIO状态。编译方法包括在Makefile中添加模块,并通过内核构建系统进行编译。
摘要由CSDN通过智能技术生成

模板

#include<linux/kernel.h>
#include<linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>

#define fly_pr_info(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
#define FLYGPIO_DEBUG_ON    1
#define FLYGPIO_DEBUG(fmt, arg...)          do {\
					if (FLYGPIO_DEBUG_ON)\
						fly_pr_info("<<-tlt->> [%d]"fmt"\n", __LINE__, ##arg);\
			} while (0)


int mycdev_open(struct inode *inode, struct file *filp)
{
	return 0; 
}

int mycdev_release(struct inode *inode, struct file *filp)
{
	return 0;
}

static ssize_t mycdev_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
	return 0;
}

static ssize_t mycdev_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
	return 0;
}


static const struct file_operations mycdev_fops =
{
	.read = mycdev_read,
	.write = mycdev_write,
	.open = mycdev_open,
	.release = mycdev_release,
};

static struct miscdevice my_misc_device = {
	.minor = MISC_DYNAMIC_MINOR,		
	.name = "my_miscdev",
	.fops = &mycdev_fops,
};

static int mygpio_probe(struct platform_device *pdev)
{
	int ret = 0;

	FLYGPIO_DEBUG("@@flygpio Probe. \r\n");

	ret = misc_register(&my_misc_device);
	if (ret != 0 )
		FLYGPIO_DEBUG("flygpio: flygpio_device register failed\n");

	return ret;
}

static int mygpio_remove(struct platform_device *pdev)
{
	
	FLYGPIO_DEBUG("flygpio remove. \r\n");
	misc_deregister(&my_misc_device);
	
	return 0;
}

 static struct platform_driver mygpio_driver = {
	.driver = {
			.name = "mygpio-dev",
			.owner = THIS_MODULE,
	},
	.remove = mygpio_remove,
	.probe = mygpio_probe,
};

static struct platform_device mygpio_device = {
    .name = "mygpio-dev",
    .id = -1,
};  

static int __init mycdev_init(void)
{
	int ret = -1;
	
	ret = platform_device_register(&mygpio_device);
	if (ret) 
	{
		FLYGPIO_DEBUG("platform_device_register_failed ");
		goto platform_device_register_failed;
	}

	ret = platform_driver_register(&mygpio_driver);
    if (ret) 
	{
       FLYGPIO_DEBUG("platform_driver_register_failed ");
       goto platform_driver_register_failed;
    }
	
	return 0;
	
platform_driver_register_failed:
	platform_device_unregister(&flygpio_device);
platform_device_register_failed:
	return ret;	
}

static void __exit mycdev_exit(void)
{
	FLYGPIO_DEBUG("mycdev exit\r\n");
	platform_driver_unregister(&mygpio_driver);
	platform_device_unregister(&mygpio_device);
}

module_init(mycdev_init);
module_exit(mycdev_exit);

MODULE_LICENSE("GPL");

添加设备树获取gpio可编译控灯

#include<linux/kernel.h>
#include<linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/fb.h>
#include <linux/init.h>
#include <generated/autoconf.h>
#include <linux/ioctl.h>
#include <linux/spinlock.h>
#include <asm/io.h>
#include <linux/irq.h>
#include <asm/atomic.h>
#include <linux/of_gpio.h>
#include <linux/time.h>
#include <linux/kthread.h>
#include <linux/types.h>
#include <linux/poll.h>
#include <linux/interrupt.h>

static struct device_node *flygpio_node = NULL;

// 设置gpio高低电平
static int  apstate_led_pin = -1;
// #define LED_ON   gpio_set_value(apstate_led_pin,0);
// #define LED_OFF  gpio_set_value(apstate_led_pin,1);
#define LED_ON  do{  gpio_set_value(apstate_led_pin,0); }while(0)
#define LED_OFF  do{ gpio_set_value(apstate_led_pin,1); }while(0)

#define fly_pr_info(fmt, arg...) printk(KERN_WARNING fmt, ##arg)
#define FLYGPIO_DEBUG_ON    1
#define FLYGPIO_DEBUG(fmt, arg...)          do {\
               if (FLYGPIO_DEBUG_ON)\
                  fly_pr_info("<<-tlt->> [%d]"fmt"\n", __LINE__, ##arg);\
         } while (0)


int mycdev_open(struct inode *inode, struct file *filp)
{
   return 0; 
}

int mycdev_release(struct inode *inode, struct file *filp)
{
   return 0;
}

static ssize_t mycdev_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
   return (ssize_t)0;
}

static ssize_t mycdev_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
   char readbuf[30];
   int ret_cnt;
   int CopyBufSize = (size < (sizeof(readbuf) - 1)) ? (size) : (sizeof(readbuf) - 1);
   int pin,value;
   // 将内核空间的数据拷贝到回调该函数的用户进程的用户进程空间
   if (copy_from_user(readbuf, buf, CopyBufSize)) 
   {

      FLYGPIO_DEBUG("@@copy_from_user() fail.\r\n");
      return -1;
   }
    
   FLYGPIO_DEBUG("@@hello write buffer :%s\n",readbuf);
   //对写入的管脚和值使用空格分开,使用sscanf分别获取
   ret_cnt = sscanf(readbuf, "%d %d",&pin, &value);
   if(ret_cnt != 2) 
   {     
      FLYGPIO_DEBUG("@@ret_cnt != 2 fail.\r\n");
      return -1;
   }

   // 判断设置的值是否合法 0 | 1
   if(value == 0)
   {
      FLYGPIO_DEBUG("@@set LED OFF. \r\n");
      LED_OFF;
   }
   else
   {
      FLYGPIO_DEBUG("@@set LED ON.\r\n");
      LED_ON;
   }
   
   FLYGPIO_DEBUG("@@you write pin %d,value = %d   \n",pin,value);
   // 内核中返回值不可为0
   return ((ssize_t)size);
}


static const struct file_operations mycdev_fops =
{
   .read = mycdev_read,
   .write = mycdev_write,
   .open = mycdev_open,
   .release = mycdev_release,
};

static struct miscdevice my_misc_device = {
   .minor = MISC_DYNAMIC_MINOR,     
   .name = "my_miscdev",
   .fops = &mycdev_fops,
};

static int mygpio_probe(struct platform_device *pdev)
{
   int ret = 0;

   FLYGPIO_DEBUG("@@flygpio Probe. \r\n");

   ret = misc_register(&my_misc_device);
   if (ret != 0 )
      FLYGPIO_DEBUG("@@flygpio: flygpio_device register failed\n");

   return ret;
}

static int mygpio_remove(struct platform_device *pdev)
{
   
   FLYGPIO_DEBUG("@@flygpio remove. \r\n");
   misc_deregister(&my_misc_device);
   
   return 0;
}

static struct platform_driver mygpio_driver = {
   .driver = {
         .name = "mygpio-dev",
         .owner = THIS_MODULE,
   },
   .remove = mygpio_remove,
   .probe = mygpio_probe,
};

static struct platform_device mygpio_device = {
    .name = "mygpio-dev",
    .id = -1,
};  

static int __init mycdev_init(void)
{
   int ret = -1;
   flygpio_node = of_find_compatible_node(NULL, NULL, "mediatek,flyrdgpio");
   if(flygpio_node)
   {
      apstate_led_pin =  of_get_named_gpio(flygpio_node,"apstate_led_gpio", 0);
      FLYGPIO_DEBUG("@@my_gpio_get_name ---------apstate_led_pin------- oK\r\n");
      if (!gpio_is_valid(apstate_led_pin)) 
      {
            FLYGPIO_DEBUG("apstate_led_pin bc_failed\n");
      }
   }

   FLYGPIO_DEBUG("@@led 1 = %d \r\n",apstate_led_pin);
   ret = gpio_request(apstate_led_pin, "apstate_led_pin");
   if (ret < 0) 
   {
      FLYGPIO_DEBUG("apstate_led_pin gpio bc_failed\n");
      //return;
   }

   gpio_direction_output(apstate_led_pin, 0);
   FLYGPIO_DEBUG("@@mycdev_init ");
   ret = platform_device_register(&mygpio_device);
   if (ret) 
   {
      FLYGPIO_DEBUG("@@platform_device_register_failed ");
      goto platform_device_register_failed;
   }

   ret = platform_driver_register(&mygpio_driver);
   if (ret) 
   {
       FLYGPIO_DEBUG("@@platform_driver_register_failed ");
       goto platform_driver_register_failed;
   }
   
   return 0;
   
platform_driver_register_failed:
   //platform_device_unregister(&flygpio_device);
platform_device_register_failed:
   return ret; 
}

static void __exit mycdev_exit(void)
{
   FLYGPIO_DEBUG("@@mycdev exit\r\n");
   platform_driver_unregister(&mygpio_driver);
   platform_device_unregister(&mygpio_device);
}

module_init(mycdev_init);
module_exit(mycdev_exit);

MODULE_LICENSE("GPL");

Makefile

在驱动源码目录下的Makefile添加

obj-m +=testgpio.o

在驱动源码的上级目录下的Makefile添加

obj-m += test/

编译方法

在总项目路径如/ac8257目录下执行

source ./build/envsetup.sh
lunch 15
mmm kernel-4.9:kernel
make bootimage
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值